Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TileGrid example that uses the built in font to display text #2566

Closed
tannewt opened this issue Jan 31, 2020 · 16 comments
Closed

Add TileGrid example that uses the built in font to display text #2566

tannewt opened this issue Jan 31, 2020 · 16 comments

Comments

@tannewt
Copy link
Member

tannewt commented Jan 31, 2020

Similar to terminalio but without using it.

@caternuson
Copy link

from discord:

Maybe a multi-line Hello World example that does not use Label would make it clearer how terminal style text could work.

@caternuson
Copy link

I'm not sure I understand what can/can't be used here? Like how far down the rabbit hole are we going?

Wouldn't a multi-line example without using Label essentially just be a recreation of the code in Label._update_text() ?

@jepler
Copy link
Member

jepler commented Jan 31, 2020

@caternuson This stems from discussion over the memory usage of Label. There is a way to display text using a built-in font that uses much less RAM memory than Label does, by having a single TileGrid rather than a TileGrid for each character.

@caternuson
Copy link

@jepler Ah, thanks. I think that was the clarification I was after.

@jepler
Copy link
Member

jepler commented Jan 31, 2020

class GridLabel(displayio.TileGrid):
    def __init__(self, font, *, text=None, max_size=None, color=0xffffff,
                 width=None, height=None, **kwargs):
        if not text and not max_size:
            raise RuntimeError("Please provide a max size, or initial text")
        cwidth, cheight = self.calc_size(text)
        width = width or cwidth
        height = height or cheight

        self._width = width
        self._height = height
        self.font = font
        self.palette = displayio.Palette(2)
        self.palette.make_transparent(0)
        self.palette[1] = color

        tile_width, tile_height = font.get_bounding_box()[:2]
        super().__init__(width=width, height=height, tile_width=tile_width,
                         tile_height=tile_height, bitmap=font.bitmap,
                         pixel_shader=self.palette,
                         default_tile=self.font.get_glyph(ord('Z')).tile_index,
                         **kwargs)
        self._update_text(text or '')

    def calc_size(self, text):
        start = 0
        width = 0
        height = 1
        while True:
            end = text.find('\n', start)
            if end == -1:
                width = max(width, len(text)-start)
                break
            width = max(width, end-start)
            height += 1
            start = end + 1
        print(width, height)
        return (width, height)

    def _update_text(self, text):
        self._text = text
        r = c = 0
        space = self.font.get_glyph(ord(' ')).tile_index
        for codepoint in text:
            if codepoint == '\n':
                for i in range(c, self._width):
                    self[i, r] = space
                c = 0
                r = r + 1
                continue
            if c == self._width:
                c = 0
                r = r + 1
            if r >= self._height: break
            self[c, r] = self.font.get_glyph(ord(codepoint)).tile_index
            c = c + 1
        while r < self._height:
            for i in range(c, self._width):
                self[i, r] = space
            c = 0
            r = r + 1
        
    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, new_text):
        if new_text != self._text:
            self._update_text(new_text)

@gmeader
Copy link

gmeader commented Feb 1, 2020

I'm the newbie that made the request in Discord. I was looking for a complete working example/demo that would run as code.py and be included in the /examples folder of the libs. I guess this class is the first step towards that.

@jepler
Copy link
Member

jepler commented Feb 1, 2020

Updated version of gridlabel (there was at least one bug, hopefully fixed): https://gist.github.com/e7a159b28048dc8637f69db17caba5ea
A silly little demo that I ran on my pygamer: https://gist.github.com/4e17ebc6b3a6e762856d2338fdfb99d9

@gmeader Being new to something is an exciting time, enjoy it!

@caternuson caternuson removed their assignment Feb 3, 2020
@jepler
Copy link
Member

jepler commented Feb 3, 2020

@gmeader We discussed this in the CIrcuitPython chat, and @tannewt would like to see this made into a pull request in the https://github.com/adafruit/Adafruit_CircuitPython_Display_Text -- both this module and an example.

Would you be interested in helping us out on this?

@gmeader
Copy link

gmeader commented Feb 3, 2020

Yes, happy to help.

@gmeader
Copy link

gmeader commented Feb 4, 2020

I think GridLabel should have a "color" property (not just the constructor param) that may be set and read.
Perhaps even a background color property that also may be set to transparent as well?

@jepler
Copy link
Member

jepler commented Feb 4, 2020

Thank you!

I definitely agree with adding a "color" property. This would make the GridLabel more like the existing Label, which has a color property.

I think adding a background constructor and property is fine, if it is useful.

@kmatch98
Copy link
Collaborator

kmatch98 commented May 19, 2020

Here is another example of using text in a tileGrid: https://github.com/kmatch98/simpleTerminal

In modifying a text editor for use with CircuitPython (see the modules branch of the MicroPython editor pye), I developed a simpleTerminal class that creates a tileGrid of text with some additions for cursor control. It has a wrapper class editorTerminal that handles some VT100 style commands.


Performance-related issue for label:

As mentioned by @jepler and @caternuson, the performance of the tileGrid is much superior to using label. I think this stems from the fact that label handles proportional fonts while tileGrid can only handle fixed width fonts.

I'm struggling with the performance of label. It seems like there should be a better way, rather than combining so many tileGrids each holding just one character. Anyone have any suggestions on a path forward?

edit: Just found the function for load_glyphs. It takes a while to load the glyphs, but the actual label creation (or text value changes) is at a more reasonable level. Feel free to ignore the question above.

glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.:?! '
font = bitmap_font.load_font("/BebasNeue-Bold-62.bdf")
font.load_glyphs(glyphs)

@tannewt
Copy link
Member Author

tannewt commented Jul 14, 2020

Is this done?

@tannewt tannewt modified the milestones: Support, Long term Jul 14, 2020
@caternuson
Copy link

I think so? Looks like it became a PR?

@adafruit-adabot adafruit-adabot added the Hacktoberfest Beginner friendly issues for Hacktoberfest event label Oct 26, 2021
@FoamyGuy FoamyGuy removed the Hacktoberfest Beginner friendly issues for Hacktoberfest event label Nov 8, 2021
@adafruit-adabot adafruit-adabot added the Hacktoberfest Beginner friendly issues for Hacktoberfest event label Sep 29, 2022
@skerr92
Copy link

skerr92 commented Oct 16, 2022

This appears to have been fixed/done back in 2020. see Display_text #75 PR

@caternuson
Copy link

closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants