GithubHelp home page GithubHelp logo

adafruit_circuitpython_display_text's Introduction

Introduction

Documentation Status

Discord

Build Status

Code Style: Black

Displays text using CircuitPython's displayio.

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Usage Example

For a board with a built-in display.

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.root_group = text_area
while True:
    pass

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

adafruit_circuitpython_display_text's People

Contributors

caternuson avatar dhalbert avatar eteq avatar evaherrada avatar flavio-fernandes avatar foamyguy avatar imnotjames avatar isacben avatar jepler avatar jerryneedell avatar jposada202020 avatar jtrip avatar kattni avatar kmatch98 avatar ladyada avatar lesamouraipourpre avatar makermelissa avatar mikerenfro avatar neoxharsh avatar neradoc avatar retiredwizard avatar rgrizzell avatar siddacious avatar snkymkrct avatar sommersoft avatar tannewt avatar tekktrik avatar tg-techie avatar theacodes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_display_text's Issues

MemoryError: memory allocation failed

I have this issue, when I use the adafruit_bitmap_font library in conjunction with Adafruit_CircuitPython_Display_Text
This the program

# Write your code here :-)
import os
import board
import displayio
from adafruit_display_text.label import Label
from adafruit_bitmap_font import bitmap_font
from adafruit_st7735r import ST7735R

spi = board.SPI()
tft_cs = board.D5
tft_dc = board.D6
rst = board.D7

displayio.release_displays()
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=rst)
display = ST7735R(display_bus, width=160, height=83, colstart=24, rowstart=1, rotation=90)
#display = ST7735R(display_bus, width=160, height=80, colstart=24, rotation=90)

# the current working directory (where this file is)
cwd = ("/"+__file__).rsplit('/', 1)[0]
fonts = [file for file in os.listdir(cwd+"/fonts/")
         if (file.endswith(".bdf") and not file.startswith("._"))]
for i, filename in enumerate(fonts):
    fonts[i] = cwd+"/fonts/"+filename
print(fonts)

##########################################################################
THE_FONT = fonts[0]
DISPLAY_STRING = "A multi-line-\nexample of\n  font bounding!"
WRAP_CHARS = 20

##########################################################################
# Make the display context
splash = displayio.Group()
display.show(splash)

# Make a background color fill
color_bitmap = displayio.Bitmap(160, 80, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette,
                               x=0, y=0)
splash.append(bg_sprite)

# Load the font
font = bitmap_font.load_font(THE_FONT)
font.load_glyphs(DISPLAY_STRING.encode('utf-8'))

print(DISPLAY_STRING)

text = Label(font, text=DISPLAY_STRING)
text.x = 20
text.y = 40
text.color = 0x0

# Make a background color fill
dims = text.bounding_box
print(dims)
textbg_bitmap = displayio.Bitmap(dims[2], dims[3], 1)
textbg_palette = displayio.Palette(1)
textbg_palette[0] = 0xFF0000
textbg_sprite = displayio.TileGrid(textbg_bitmap,
                                   pixel_shader=textbg_palette,
                                   x=text.x+dims[0], y=text.y+dims[1])
splash.append(textbg_sprite)
splash.append(text)
board.DISPLAY.refresh_soon()
board.DISPLAY.wait_for_frame()

while True:
    pass

and this is the error.

>>> import text3
['/fonts/Helvetica-Bold-16.bdf', '/fonts/Alef-Bold-18.bdf', '/fonts/Arial-12.bdf', '/fonts/Comic-Bold-18.bdf', '/fonts/Noto-18.bdf', '/fonts/Verdana-Bold-18.bdf']
A multi-line-
example of
  font bounding!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "text3.py", line 52, in <module>
  File "adafruit_display_text/label.py", line 79, in __init__
  File "adafruit_display_text/label.py", line 114, in _update_text
MemoryError: memory allocation failed, allocating 92 bytes
>>> 

Speed up glyph loading when glyphs are not pre-loaded

When creating a text label: label processes each character at a time with get_glyph. If font glyphs are not preloaded, the adafruit_bitmap_font library function get_glyph calls the load_glyphs command on each individual character.

The load_glyphs function parses each line of the font file until the required glyph is found. So, if we process each character individually (like we do now), each new glyph that is encountered will require a new parsing of the font file.

I propose to perform the load_glyphs command on the full text input string prior to entering the character loop. By performing load_glyphs on the full input string will require a maximum of one time parsing through the font file.

When the glyphs are already loaded, this will add some time overhead due to checking if the glyphs are already present. But this checking adds only a small overhead (see snippet below from load_glyphs).

https://github.com/adafruit/Adafruit_CircuitPython_Bitmap_Font/blob/784322cac41f3ae33385675e9977dd3957f6cecb/adafruit_bitmap_font/bdf.py#L100-L104

for code_point in remaining:
            if code_point in self._glyphs and self._glyphs[code_point]:
                remaining.remove(code_point)
        if not remaining:
            return

display_text_simpletest.py is blank, not functional.

Hello, while looking into this library the first time I noticed that the display_text_simpletest.py is blank. The README.md file illustrates a simple test that I think would be great, however I would also like to suggest making one small improvement.

Currently the usage example is:

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)

Which does seem to work in my testing, however after updating the display with the text_area object the code immediately ends which leads to circuitpython displaying the message that the code is done running. My only concern is that beginners might not have the intuition to think that it is working fine but some additional control needs to be used in order for it to be visible for more than a moment, and then the beginner might be chasing down a ghost thinking it isn't working right.

I think a beginner friendly improvement would be to add a delay so that they should be able to see the output but then also see that when the code is done executing it will be replaced by the circuit python "Code done running" message.
Like so:

import board
import terminalio
from adafruit_display_text import label
from time import sleep

text = "Hello world"
text_area = label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
sleep(3)

Another simple option might be to put the board.DISPLAY.show call in a loop (maybe infinite like while True:) but maybe that's not setting a great example for beginners or is otherwise adding irrelevant logic to the example.

I would be happy to make these changes and submit a pull request. I don't think I have submitted a pull request to any of your repos yet so I thought I would introduce the idea here. Perhaps there is some reason that example is currently missing or if you have any thoughts about the change please let me know.

Will fail if font does not have expected glyphs

Not all fonts have all expected characters used to check height. Maybe add some try/except to catch this?

Adafruit CircuitPython 5.3.0 on 2020-04-29; Adafruit Circuit Playground Bluefruit with nRF52840
>>> from adafruit_bitmap_font import bitmap_font
>>> from adafruit_display_text import label
>>> font = bitmap_font.load_font("/monoMMM_5_90.bdf")
>>> my_label = label.Label(font, text="hello", color=0xFFFFFF)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_display_text/label.py", line 122, in __init__
  File "adafruit_display_text/label.py", line 264, in _update_text
  File "adafruit_display_text/label.py", line 144, in _create_background_box
AttributeError: 'NoneType' object has no attribute 'height'
>>> glyph = font.get_glyph(ord("M"))
>>> type(glyph)
<class 'Glyph'>
>>> glyph = font.get_glyph(ord(" "))
>>> type(glyph)
<class 'NoneType'>
>>> glyph = font.get_glyph(ord("j"))
>>> type(glyph)
<class 'NoneType'>
>>> 

Should setting background_tight=True change the label's bounding box?

I have two labels with different sized fonts which I would like to place next to each other along the same baseline. My solution was to place the one on the right in relation to the one on the left using the information in the left's bounding box. This is still a bit off though because the labels have different font sizes so each label has a different amount of padding at the bottom (where the descenders go).

These labels have a contrasting background color and I noticed that when I set background_tight on a label containing numerals that the padding at the bottom disappears and the bottom of the label seems to coincide with the font's baseline. Unfortunately, doing this doesn't change the bounding box. If it did, that would make laying out my numerals a lot easier. And the code would still work after changing the font, adjusting margins or possibly dragging multiple labels around with a touchscreen.

FoamyGuy helped me with a workaround that works fine in my app but this seems useful. I guess the downside is that it won't be very useful for text since a lot of it will have descenders.

Maybe its not worth the trouble? I guess this is more hacky than I originally thought and maybe it would break existing code. However, it does seem to make sense that the bounding box should move when the padding changes.

Show a better message when exceeding max_glpyhs / initial text length

Maybe I'm incorrectly assuming the mutability of a Label? You can reassign the text, but if it is longer than the original text, then you exceed a Group limit.

Adafruit CircuitPython 4.0.0 on 2019-05-20; Adafruit PyPortal with samd51j20
>>> import terminalio
>>> from adafruit_display_text import label
>>> label = label.Label(terminalio.FONT, text="123456789")
>>> label.text = "1"
>>> label.text = "1234"
>>> label.text = "1234567"
>>> label.text = "123456789"
>>> label.text = "1234567890"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_display_text/label.py", line 174, in text
  File "adafruit_display_text/label.py", line 119, in _update_text
RuntimeError: Group full
>>>

Docs link in readme doesn't work

It takes me to a page that says

        \          SORRY            /
         \                         /
          \    This page does     /
           ]   not exist yet.    [    ,'|
           ]                     [   /  |
           ]___               ___[ ,'   |
           ]  ]\             /[  [ |:   |
           ]  ] \           / [  [ |:   |
           ]  ]  ]         [  [  [ |:   |
           ]  ]  ]__     __[  [  [ |:   |
           ]  ]  ] ]\ _ /[ [  [  [ |:   |
           ]  ]  ] ] (#) [ [  [  [ :===='
           ]  ]  ]_].nHn.[_[  [  [
           ]  ]  ]  HHHHH. [  [  [
           ]  ] /   `HH("N  \ [  [
           ]__]/     HHH  "  \[__[
           ]         NNN         [
           ]         N/"         [
           ]         N H         [
          /          N            \
         /           q,            \
        /                           \

y position of text can be wrong if constructor does not specify text

I updated my libraries last night to ones from adafruit-circuitpython-bundle-5.x-mpy-20200806.zip. I noticed the performance improvement with moving around text but I also spotted one solitary piece of text that was misplaced slightly off screen.

I've just made a simple recreation of this, I think it's when text is not specified or it is empty string, y is set, and then text is set. I am using scaled text here.

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 5.3.0 on 2020-04-29; Adafruit CLUE nRF52840 Express with nRF52840
>>>
>>> import displayio, terminalio, board
>>> from adafruit_display_text.label import Label
>>> fdim = terminalio.FONT.get_bounding_box()
>>> l1 = Label(terminalio.FONT, max_glyphs=9, scale=3, color=0xff0000)
>>> l2 = Label(terminalio.FONT, text="", max_glyphs=9, scale=3, color=0x00ff00)
>>> l3 = Label(terminalio.FONT, text="Chad", max_glyphs=9, scale=3, color=0x0000ff)
>>> l1.y = l2.y = l3.y = round(240 - (3 * fdim[1] / 2))
>>> (l1.y, l2.y, l3.y)
(219, 219, 219)
>>> l2.x = 80
>>> l3.x = 160
>>> tg = displayio.Group(max_size=3)
>>> tg.append(l1)
>>> tg.append(l2)
>>> tg.append(l3)
>>> board.DISPLAY.show(tg)
>>> l1.text="Wot"
>>> l2.text="No"
>>> (l1.y, l2.y, l3.y)
(240, 240, 219)

Only l3 is correctly position, l1 and l2 are half off screen.

I see #78 which sounds like it could be in the same area?

Setting to whitespace seems to be a workaround for me, e.g. text=" ", and might be able to re-order my code to set text once in constructor.

Don't allocate a background bitmap when background_color is None

I'm getting this even when background_color is None.

  File "code.py", line 50, in <module>
  File "code.py", line 47, in <module>
  File "adafruit_pyportal.py", line 1028, in fetch
  File "adafruit_pyportal.py", line 601, in set_text
  File "adafruit_display_text/label.py", line 123, in __init__
  File "adafruit_display_text/label.py", line 295, in _update_text
  File "adafruit_display_text/label.py", line 205, in _update_background_color
  File "adafruit_display_text/label.py", line 162, in _create_background_box
MemoryError: memory allocation failed, allocating 3780 bytes

Label disappears after text parameter is changed more than once.

When I create a label, and then update it's text parameter later, the text will completely disappear upon the second change.

code:

label = Label(terminalio.FONT, x=10, y=32, text="Test1", max_glyphs=5, color=0xFFFFFF)
group.append(label)

time.sleep(1)
label.text = "Test2"
time.sleep(1)
label.text = "Test3"
time.sleep(1)
label.text = "Test4"
time.sleep(1)

After "Text2" It will disappear, although, sometimes I will see "Test3" For a fraction of a second.

Perhaps I am using this wrong, in which case any help would be much appreciated!

bitmap_label issue with lowercase letters

I have discovered this example script (it's a trimmed down example from bitmap_font):

import board
from adafruit_display_text import bitmap_label as label
from adafruit_bitmap_font import bitmap_font

display = board.DISPLAY

font_file = "fonts/LeagueSpartan-Bold-16.bdf"


text = "HELLO WORLd"  #  ValueError
#text = "HELLO WORLD" #  works

font = bitmap_font.load_font(font_file)
color = 0xFF00FF

# Create the tet label
text_area = label.Label(font, text=text, color=color)

# Set the location
text_area.x = 20
text_area.y = 20

# Show it
display.show(text_area)

while True:
    pass

When the text has any lower case letters in it the bitmap_label will raise this exception:

Traceback (most recent call last):
  File "code.py", line 17, in <module>
  File "/lib/adafruit_display_text/bitmap_label.py", line 124, in __init__
  File "/lib/adafruit_display_text/bitmap_label.py", line 241, in _reset_text
  File "/lib/adafruit_display_text/bitmap_label.py", line 437, in _place_text
  File "/lib/adafruit_display_text/bitmap_label.py", line 461, in _blit
ValueError: out of range of target

The text with all upper case letters does render correctly however. label does not have the same issue, it will render both text versions fine.

I'm not sure what the root cause of this issue is, perhaps something odd within this specific font? The font is here

Tested on:

Adafruit CircuitPython 6.2.0-beta.3-36-g103632f44 on 2021-03-07; Adafruit PyPortal with samd51j20

@kmatch98 I'm interested if you have any ideas about it this if you get a moment to check it out.

Error in examples/display_text_simpletest.py

I have the recent Adabox016 (Adafruit Matrix Portal) and when I try to use the simpletest.py, I get:

Traceback (most recent call last):
  File "code.py", line 10, in <module>
AttributeError: 'module' object has no attribute 'DISPLAY'

I'm using the library from adafruit-circuitpython-bundle-6.x-mpy-20201030

x position gets shifted over time when changing the text beingdisplayed

This sample code illustrates the issue:

import board
import time
import terminalio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font

text = "Helloworld"
font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf")
text_area = label.Label(font, text=text*5)
text_area.anchor_point = (0.75,0)
text_area.anchored_position = (190, 10)

board.DISPLAY.show(text_area)

i = 0
while True:
    time.sleep(0.01)
    if i % 2 == 0:
        text_area.text = "Hello world1".format(i)
    else:
        text_area.text = "Hello\nworld {}".format(i)
    i += 1

The label will move itself left until it reaches the edge of the screen.

This appears to be a rounding issue with floating point math in the anchored_position getter and setter which get called when the text is updated.

Reduce memory usage for text creation: bitmap_label

In order to reduce the amount of memory for displaying text, @FoamyGuy and I are developing a new "label" class that will use a bitmap instead of a group of TileGrids to store the text. Here is a proposed strategy for this new "bitmap_label" Class:

bitmap_label Class definition

  • Input parameters:

    • Make text a required parameter (Note: This will flag if someone creates a bitmap_label with no text, which doesn’t make any sense.)
    • For direct compatibility with label, keep the max_glyphs parameter, but ignore it.
  • Do we want to keep self._memorySaver? (Note: If so, update this to a class variable)

    • True - do not save the text value
    • False - save the text value
    • If we keep this option, then we need to create a getter for text, returns None if self._memorySaver == True.
  • Since the bitmap_label has limited edit capability after creation, minimize the instance variables that are stored

  • Add getters/setters for:

    • anchor_point
    • anchor_position
    • color
    • background_color
    • bounding_box (x,y, w,h)
  • Getters only (or does it regenerate from scratch if this is changed?)

    • font
    • line_spacing
    • text (returns None if text is not stored with _memory_saver option)
  • Add scale capability (this should be handled in the Group)

General steps for _init_ of a bitmap_label instance:

  1. Error-checking: If text is “”, raise an exception.
  2. Calculate the text box size, including any newlines and tabs
  3. Calculate the background box size, including padding
    Note: Negative padding cannot be used. (This would require adding a third color to the palette, which would inflate the bitmap_label bitmap memory usage.)
  4. Determine the bitmap size required by comparing the text box and background box max x,y dimensions.
  5. Determine start location of text in the bitmap
  6. Initialize the palette, TileGrid (self), Bitmap
  7. Draw the background fill, as required
  8. Place the text in the bitmap
  9. Set the TileGrid x,y placement based on anchor_point and anchor_position.
  10. Updated bounding_box values.

Capital M must be in font

Would be nice if the documentation of the font parameter also explicitly said something to the effect of "must include M glyph".

Exception thrown if text is not set on creation but updated later

The recent changes in 2.6.0 have introduced an exception if the text is not set on a label when it is created, but is set later.

To reproduce:

import board
import terminalio
from adafruit_display_text import label


text = "Hello world"
text_area = label.Label(terminalio.FONT, max_glyphs=15)
text_area.x = 10
text_area.y = 10
text_area.text = text
board.DISPLAY.show(text_area)
while True:
    pass

This is a version of the SimpleTest example but instead of setting the text in the Label constructor, the text is set later.

Not setting the text parameter causes the _boundingbox property to be initialized to None.

When the text property is set later, the property setter retrieves the anchored_position value:

@text.setter
def text(self, new_text):
    current_anchored_position = self.anchored_position

This in turn uses the bounding box and assumes that it has a value rather than being None:

@property
def anchored_position(self):
    """Position relative to the anchor_point. Tuple containing x,y
       pixel coordinates."""
    return (
        int(
            self.x
            + self._boundingbox[0]
            + self._anchor_point[0] * self._boundingbox[2]
        ),
        int(
            self.y
            + self._boundingbox[1]
            + self._anchor_point[1] * self._boundingbox[3]
        ),
    )

This raises an exception:

Traceback (most recent call last):
  File "code.py", line 109, in <module>
  File "adafruit_display_text/label.py", line 241, in text
  File "adafruit_display_text/label.py", line 281, in anchored_position
TypeError: 'NoneType' object is not subscriptable

The workaround is to always set the text in the constructor. A quick fix could be to change the default value from None to "", that way the bounding box is always created.

Setting anchor_point and anchored_position in constructor broken for bitmap_label

fails with this error message:

Traceback (most recent call last):
  File "code.py", line 136, in <module>
  File "/lib/adafruit_display_text/bitmap_label.py", line 146, in __init__
  File "/lib/adafruit_display_text/bitmap_label.py", line 201, in _reset_text
  File "/lib/adafruit_display_text/bitmap_label.py", line 656, in anchor_point
  File "/lib/adafruit_display_text/bitmap_label.py", line 672, in anchored_position
AttributeError: 'Label' object has no attribute '_bounding_box'

label is unaffected by this issue.

Remove usage of 0-width/height bitmaps and tilegrids

I discovered this when working on Blinka Displayio and looking at the circuitpython code as well, it appears a divide by zero error is happening in the background, but it's silently recovering from that. In order to avoid that, we'd like to add warnings if 0-width/height bitmaps are used, but it should be removed from here first as that would break this library.

It's being used here: https://github.com/adafruit/Adafruit_CircuitPython_Display_Text/blob/master/adafruit_display_text/label.py#L113

I believe it's also using 0-width or height later in the code as well, though I can't pinpoint the exact location.

I put a workaround in place for Blinka Displayio for now. See adafruit/Adafruit_Blinka_Displayio#27 (review) for more info.

When using background setter, background text does not show correctly

When ussing the setter for background text, the text does not show correctly. I am assuming that this applies for anchor point setter, as I was receiving complains from the code that I was testing. However I thought it was my new PR. Did not test this for anchor_point.

So sorry for not to catching this before the Refactor, but normally I do all the test with list iterations. sorry @FoamyGuy .

Test Code

import terminalio
import displayio
from os import uname
if uname()[0] == 'samd51':
    import board
else:
    from blinka_displayio_pygamedisplay import PyGameDisplay
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font

if uname()[0] == 'samd51':
    display= board.DISPLAY
else:
    display = PyGameDisplay(width=320, height=240)
splash = displayio.Group(max_size=10)
MEDIUM_FONT = bitmap_font.load_font("fonts/LibreBodoniv2002-Bold-10.bdf")



bitmap = displayio.Bitmap(4, 320, 2)
palette = displayio.Palette(2)
palette[0] = 0x004400
palette[1] = 0x00FFFF
tile_grid = displayio.TileGrid(bitmap,
                               pixel_shader=palette,
                               x=155,
                               y=0)
splash.append(tile_grid)

bitmap = displayio.Bitmap(320, 4, 2)
tile_grid = displayio.TileGrid(bitmap,
                               pixel_shader=palette,
                               x=0,
                               y=110)
splash.append(tile_grid)


text = "CircuitPython"
text_area = label.Label(MEDIUM_FONT,
                        text=text,
                        x=155,
                        y=155,
                        padding_left=10,
                        padding_top=10,
                        padding_bottom=10,
                        background_color = 0x990099,
                        padding_right=10)

splash.append(text_area)

text = "CircuitPython"
text_area = label.Label(MEDIUM_FONT,
                        text=text,
                        background_tight=True,
                        padding_left=10,
                        padding_top=10,
                        padding_bottom=10,
                        padding_right=10)
text_area.x = 155
text_area.y = 110
text_area.background_color = 0x990099
splash.append(text_area)


display.show(splash)

Results

image

bitmap_label does not show text if not initialized with something.

bitmap_label will not draw text if it's set after creation instead of passing text in the constructor

import board
import terminalio
from adafruit_display_text import bitmap_label
from adafruit_display_text import label

text = "Hello world"
# text_area = label.Label(terminalio.FONT, max_glyphs=50)  # regular label does show the text afterward.

text_area = bitmap_label.Label(terminalio.FONT)
# text_area = bitmap_label.Label(terminalio.FONT, text=" ") # if we init with a space it will show the text
text_area.text = text
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
while True:
    pass

I can take a look into making the bitmap_label work the same as label in this scenario. Also am curious if @kmatch98 have any ideas if you have a chance to take a look.

Attribute error when attempting to use a kanji font

I'm attempting to load a 16 point kanji font into Circuitpython (attached)
kanji16.bdf.zip
, but I'm encountering the following error:

Traceback (most recent call last):
  File "code.py", line 78, in <module>
  File "adafruit_display_text/label.py", line 90, in __init__
  File "adafruit_display_text/label.py", line 98, in _update_text
AttributeError: 'NoneType' object has no attribute 'height'

I'm not sure if this is related to the font itself - is it possible for a .bdf to not include the correct glyph properties for this library? It loads correctly in FontForge.

Changing the label text causes a change in the text position

Using the example file display_text_background_color_padding.py the text "none" is changed to say "text". In the process, the "text" label changes position and walks down the screen.

I think that either the getter or setter for anchored_position is not working properly.

anchor_point and anchored_position do not work well with scale

I updated my libraries (from adafruit-circuitpython-bundle-5.x-mpy-20200625) and tried this,

Adafruit CircuitPython 5.3.0 on 2020-04-29; Adafruit CLUE nRF52840 Express with nRF52840
>>> import terminalio, displayio, board
>>> from adafruit_display_text import label
>>> text_area = label.Label(terminalio.FONT, text="Scale!", scale=5, color=0xc0c0c0)
>>> board.DISPLAY.show(text_area)
>>> text_area.anchor_point
(0, 0)
>>> text_area.anchored_position
(0, -7)
>>> text_area.anchored_position = (0, 0)  ### expectation is text will be on screen at top left

The position of that text is not entirely on screen, the top is chopped off. This is presumably due to issues with a scale which isn't the default value of 1. Discussed this a little bit recently with @FoamyGuy in Discord.

Empty text string causes a Label's y-attribute to change

After a single character label with an empty text-attribute is defined, the label's y-attribute is incremented by 7 when the label's text-attribute is loaded with a character (TEST 1). Conversely, if the label is defined with a character in the text-attribute, the y-attribute will decrement by 7 when the text-attributed is emptied (TEST 3). In either case, the y-attribute shouldn't change. Looks like something associated with the anchor point calculation updating the y-attribute.

Adafruit CircuitPython 5.3.1 on 2020-07-13; Adafruit ItsyBitsy M4 Express with samd51g19
CircuitPython 5.x Library Bundle 20210-08-26

Test code:

from   adafruit_display_text.label   import Label

font_0 = terminalio.FONT  # Internal font

print('CircuitPython 5.x Library Bundle 20210-08-26')
address = (12, 14)
print('adress:', address)

print()
print('TEST 0: pre-load Label text, change text later')
test_0 = Label(font_0, text='0', color=0xFFFFFF, max_glyphs=1)
test_0.x, test_0.y = address
print('x =', test_0.x, 'y=', test_0.y)
test_0.text = '1'
print('x =', test_0.x, 'y=', test_0.y)

print()
print('TEST 1: no Label text, change text later')
test_1 = Label(font_0, text='', color=0xFFFFFF, max_glyphs=1)
test_1.x, test_1.y = address
print('x =', test_1.x, 'y=', test_1.y)
test_1.text = '1'
print('x =', test_1.x, 'y=', test_1.y)

print()
print('TEST 2: no Label text, no text in change')
test_2 = Label(font_0, text='', color=0xFFFFFF, max_glyphs=1)
test_2.x, test_2.y = address
print('x =', test_2.x, 'y=', test_2.y)
test_2.text = ''
print('x =', test_2.x, 'y=', test_2.y)

print()
print('TEST 3: pre-load Label text, no text in change')
test_3 = Label(font_0, text='0', color=0xFFFFFF, max_glyphs=1)
test_3.x, test_3.y = address
print('x =', test_3.x, 'y=', test_3.y)
test_3.text = ''
print('x =', test_3.x, 'y=', test_3.y)

REPL output:

>>> 
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
CircuitPython 5.x Library Bundle 20210-08-26
adress: (12, 14)

TEST 0: pre-load Label text, change text later
x = 12 y= 14
x = 12 y= 14

TEST 1: no Label text, change text later
x = 12 y= 14
x = 12 y= 21

TEST 2: no Label text, no text in change
x = 12 y= 14
x = 12 y= 14

TEST 3: pre-load Label text, no text in change
x = 12 y= 14
x = 12 y= 7

Press any key to enter the REPL. Use CTRL-D to reload.```

`label.py` does not allow `color=None`

When using label.py to create transparent text with color=None the following error is received:

  File "/lib/adafruit_display_text/label.py", line 105, in __init__
TypeError: color buffer must be a buffer, tuple, list, or int

Here is my input code:

from adafruit_display_text import label
...
text_area = label.Label(terminalio.FONT, text="Hello world", color=None)

The only time I envision that a Label’s color might be desired to be set to None is when using the builtinFont where the background is done the “old way” that saves memory on the Clue.

In bitmap_label.py we currently accommodate transparent text.

Main question: Should we accommodate transparent text color with label.py? There are two cases where this might be used:

  1. Using transparent text as a way of hiding it.
  2. Using BuiltinFont with the “old way” of creating the background color and using transparent text.

Failing to Deploy

Ok, so when I pushed a release, I noticed it was failing on deploy because setup.py is missing. So it looks like we either need to create a setup.py file or to set env: - DEPLOY_PYPI="false" in .travis.yml so it doesn't attempt to deploy.

Label could have a background color

Right now only the text color can be selected, and the background color is transparent.
Being able to optionally define the background color would be great.

builtin font does not have load_glyphs always

in #85 we add a call to load_glyphs inside of _update_text and this made the label building / rendering work faster.

It looks like in some cases however this is resulting in an error when used with builtin font:

Traceback (most recent call last):
  File "code.py", line 15, in <module>
  File "adafruit_clue.py", line 913, in simple_text_display
  File "adafruit_clue.py", line 117, in __init__
  File "adafruit_clue.py", line 128, in add_text_line
  File "adafruit_display_text/label.py", line 125, in __init__
  File "adafruit_display_text/label.py", line 240, in _update_text
AttributeError: 'BuiltinFont' object has no attribute 'load_glyphs'

This was pointed out by a user in the #help-with-circuitpython channel on discord. They were working on the Clue Temperature and Humidity example project from here: https://learn.adafruit.com/adafruit-clue/clue-temperature-and-humidity-monitor I was able to recreate it with that project on a CLUE.

But I do suspect this issue might be more wide spread, perhaps any label that is using terminalio.FONT.

I think we could resolve this by putting the load_glyphs call inside of an if statement checking to make sure we aren't currently using terminalio.FONT

Multiline text is no longer vertically centred around the all of the text lines

I just tested the CLUE sensor plotter with latest libraries from the 20201020 bundle and noticed its button guide screen has the text incorrectly positioned. You can see how it should look from the image at the top of https://learn.adafruit.com/clue-sensor-plotter-circuitpython/circuitpython-sensor-plotter but now it appears with the first line saying Button Guide half way down the screen.

I think this code reproduces the problem. Line 1 initially appears in the middle of the screen but then stays exactly where it is at lines are added. Judging by the plotter code this wasn't the behaviour of the original library with multi-line text.

Adafruit CircuitPython 5.3.1 on 2020-07-13; Adafruit CLUE nRF52840 Express with nRF52840
>>>
>>> import displayio
>>> import terminalio
>>> import board
>>> import time
>>> from adafruit_display_text.label import Label
>>> text = Label(terminalio.FONT, text="line 1", max_glyphs=200)
>>> board.DISPLAY.show(text)
>>> text.y = board.DISPLAY.height // 2
>>> for lines in range(2, 13 + 1):
...     text.text = "\n".join(["Line " + str(line) for line in range(1, lines + 1)])
...     time.sleep(2)
...
...
...

I just confirmed this using Label from an older version of the library (27-Mar-2020) and the text stays centred on the screen as it grows and all the lines fit on the screen.

>>> from adafruit_display_text_20200327.label import Label

List index out of range

It turns out the issue with skipping the glyphs with zero-length tilegrids results in a List index out of range error:

Traceback (most recent call last):
  File "electioncal.py", line 58, in <module>
    gfx.elections_cycle()
  File "/home/pi/electioncal_graphics.py", line 86, in elections_cycle
    self.election_name_text_line2.text, self.election_name_text.text = self.paragrapher(self.electioncal["dates"][i]["name"], 40)
  File "/home/pi/.local/lib/python3.7/site-packages/adafruit_display_text/label.py", line 362, in text
    self._update_text(str(new_text))
  File "/home/pi/.local/lib/python3.7/site-packages/adafruit_display_text/label.py", line 292, in _update_text
    self[i].position = (position_x, position_y)
  File "/home/pi/.local/lib/python3.7/site-packages/displayio/group.py", line 142, in __getitem__
    return self._layers[index]
IndexError: list index out of range

Perhaps a better solution would be to check the width and height of the glyph and if zero, just substitute a 1. That essentially how I was doing it as a work-around, though it's possible that may cause text alignment issues. Another option may be just putting a None in there for face as an empty placeholder and checking for that when the text is rendered.

Updated documentation for label.py to clarify usage for background

@FoamyGuy Here are my collection of thoughts on updates for the learn guide for adafruit_display_text\label.py. I just realized that maybe this belongs in a separate repository with the learn guides, but I couldn't identify the location. If you know an alternate location, let me know. If you have time to review this list, please add your suggestions and then we can discuss how you want to coordinate or divvy-up any work on the learn guide.

Documentation updates:

  • Briefly describe differences in font typefaces: Fixed width vs variable width (proportional). We can handle both! Explain that BuiltinFont's terminalio.FONT can be used with a TileGrid resource-efficiently since it is a fixed-size font. (There is an open issue over in circuitpython about using TileGrid with BuiltinFont (issue adafruit/circuitpython#2566.)

  • Define the baseline position (halfway up the M glyph). There is already an image in the current learn guide. Indicate that is is mostly important if you are formatting multiple lines of text and they need to align. Define ascenders/descenders, since this useful for understanding the background options.

  • anchor_point and anchor_position: reference the candy hearts example

Explain background size options:

  • background_tight = False (default): Background dimensions include room for ascenders and descenders for the font, even if the text does not have any ascenders/descenders. [Note: Ascenders and descender dimensions are sampled from these letters: M, j, ' (apostrophe)]

  • background_tight = True: Background dimensions are set with the minimum bounding box for the text.

  • padding_*: adds (positive numbers) or subtracts (negative numbers) this many pixels from the bounding box on the specified side (_top, _bottom, _left, _right)

Special tips on BDF loaded fonts:

  • Explain how to reduce BDF font file size: Remove any extraneous glyphs manually with a text editor
  • Reference the Adobe BDF format definition for loaded fonts in BDF format: Document here

Add one additional font to the library

The base_alignment example script uses two fonts, but only one is currently checked in to the repo.

We can find a permissively licensed extra font to include so that the example can run with only files contained in the repo.

Feature request: anchor relative to baseline

Anchoring text along a baseline (rather than or in addition to bounding rect) would be very Very very helpful. Maybe this could be indicated without breaking existing code by expressing a Label’s anchor_point as a single value or single-element tuple rather than a 2-element tuple (so it still can do left/center/right alignment, while y coord is then just the baseline, period).

As it currently stands, text bounds can vary with descenders, punctuation, etc. This makes it impossible to guarantee a consistent baseline when there are multiple Label elements that are trying to align as a well-formatted and legible unit. Also, for text that changes value, the current use of bounding rect alignment can cause Label elements to move up or down as the value changes, rather than maintaining their original baseline.

Attached image shows example of desired baseline behavior, which was approximated with some hacks. For the first two items on each line, baseline alignment is forced by using bottom alignment and applying upper() to the location strings (though none of these locations have descenders…but if any of them did, say a “j” or “g,” and were not upper() filtered, those descenders would alter the text bounds, placing the Label bottom-aligned by bounds, but with a baseline that jumps up a few pixels and Looks Bad). The third element on each line here is also bottom aligned…but with +2 added to each anchored position’s Y value…it works here because we know that a comma in this font and this size descends 2 pixels below the baseline, but that’s just a quick workaround and not going to be true for all fonts and sizes. Baseline anchoring would take care of all of that.

baseline

`y_offset` should not include any impact due to newlines '\n'

The y_offset is currently incorrectly calculated with the inclusion of a multiple related to the quantity of newlines '\n' in the text string.

However y_offset should be independent of the number of lines in the string, and should just be related to the glyph dimensions, since this acts as a baseline offset to the vertical center of the "M" glyph.

I observed this issue when calibrating text to the upcoming bitmap_label.py file.

Try to remove max_glyphs restriction from label

Making an issue now so that we keep this in mind. I do think we'll want to hold off on making this change at least until there is a stable release made that includes the changes to Group though so it might be a little bit until we actually need to do anything further.

displayio.Group has been updated to allow it's size to be mutable so more things can be added, and there is no need to use the max_size any longer.

We will be able to change label.Label to make use of this and remove the max_glyphs restriction.

Awkward usage of Label with x,y, then anchor_point and anchored_position

Currently, the label instance position is defined by x and y when the instance is created. Then the anchored_position and anchor_point setters can be used only after the instance is created.

I think it would be more intuitive if the anchor_point and anchored_position were considered as the "default" input parameters and that these parameters be made available when creating a label instance.

Consider offering control over creation of background bitmap to reduce memory usage

I've not followed the recent changes to this library but somewhere since https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/tag/20200327 an extra bitmap is created for a background feature. This is the likely candidate for the primary cause of a MemoryError exception that now occurs using this library for the application in Adafruit Learn: CLUE Sensor Plotter in CircuitPython. An example of this exception output can be seen in the description of the second issue in Adafruit Forums: Clue_Plotter Problem.

This may affect other existing applications too. I'd guess ones with lots of text on screen, large (possibly scaled) text and/or memory tight ones are more at risk.

I'm not sure what the new bitmap is for but a decision on whether this feature should be off by default would be useful and dictate whether existing applications need testing/reviewing/changing.

Duplicate code in library files - potential refactor needed

actions failure with details on duplicated sections is here

We want to avoid having duplicated code if possible. One way to avoid it here will be to make a LabelBase class in __init__.py with the duplicated parts and extend that in the other types of labels.

When text width changes, artifacts are left...

I noticed this after it had been running hours. When the text shrinks after a text update due to a variable width font, artifacts are left over. Here's the open weather demo running on a PyPortal.

IMG_2240

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.