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 LedDisplay widget #2990

Closed
wants to merge 9 commits into from

Conversation

eliasdorneles
Copy link

Here is a first attempt of implementation for a widget to display 7-segment display-like digits and more.

This works for digits all in the same line, but it needs to be adapted for the cases where the digits don't fit.

Please review the following checklist.

  • Docstrings on all new or modified functions / classes
  • Updated documentation
  • Updated CHANGELOG.md (where appropriate)

Here is a first attempt of implementation for a widget to display
7-segment display-like digits and more.

This works for digits all in the same line, but it needs to be adapted
for the cases where the digits don't fit.
@eliasdorneles
Copy link
Author

So this implementation works for digits in the same "line":

image

It breaks when the digits fall outside the "line":

image

I would love to be able to use CSS to solve this problem, since it seems the perfect job for layout: horizontal.

I tried creating a compound widget with that idea, but ran into two problems:

  • couldn't get the horizontal layout working for my single digit Static LedDisplay
  • when adding digits reactively, how to refresh / re-compose() ?

I will try to continue on this idea, but would love to hear if anyone has any better idea on how to do this.

"""

# here we strip spaces and replace underscores with spaces
_character_map = {k: v.strip() for k, v in _character_map.items()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably save a bit of time if we replace the underscores with spaces right away, no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, updated!

@rodrigogiraoserrao
Copy link
Contributor

I believe you can't really re-compose. What you'd do is use .remove and .mount to dynamically remove/add widgets to the DOM hierarchy.

Maybe the solution is just to truncate on one end if it doesn't fit. @willmcgugan what do you think?

@eliasdorneles
Copy link
Author

Right, I ended up figuring out the .remove and .mount thing and updated the widgets to do that -- I got a bit carried away with it this evening, as you can imagine! 😆

The current implementation doesn't break visually anymore, now the content that doesn't fit is overflowing outside the screen.

@eliasdorneles
Copy link
Author

eliasdorneles commented Jul 22, 2023

Current status:

image

@eliasdorneles
Copy link
Author

eliasdorneles commented Jul 22, 2023

Code of testing app:

import sys

from textual.app import App, ComposeResult
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Footer, Header, Static
from textual.widgets import Input
from textual.widgets import LedDisplay
from textual.widgets._led_display import _character_map


class MyApp(App):
    BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]

    def compose(self) -> ComposeResult:
        yield Header()
        yield Footer()
        yield Input(placeholder="Type something:")
        yield LedDisplay("EuroPython 2023", id="panel")

        alphabet = "".join(k for k in _character_map)
        split_point = alphabet.index("z") + 1
        yield Static("Digits and letters: " + alphabet[:split_point])
        yield LedDisplay(alphabet[:split_point])
        yield Static("Punctuation: " + alphabet[split_point:])
        yield LedDisplay(alphabet[split_point:])
        yield Static("Chord notation:  C#m   Db min   F#7")
        yield LedDisplay("C#m   Db min   F#7")

    def on_input_changed(self, event: Input.Changed) -> None:
        display: LedDisplay = self.query_one("#panel")
        display.digits = event.value


if __name__ == "__main__":
    app = MyApp()
    app.run()

@eliasdorneles eliasdorneles changed the title [WIP] Add LedDisplay widget Add LedDisplay widget Jul 22, 2023
@rodrigogiraoserrao
Copy link
Contributor

Hey Elias, this is looking awesome! Given your most recent screenshot, it looks like the led display is now taking up 4 rows, and the bottom one is only used for the letters fgjpqy?

@eliasdorneles
Copy link
Author

eliasdorneles commented Jul 23, 2023 via email

@eliasdorneles
Copy link
Author

Okay, so I've improved several characters of the "font", and I've added an allow_lower mode to turn on the support for lower case, which I'm leaving off by default because it requires extra height.
I've also added programatically plus snapshot tests.

Here's what's looking like:

image

I believe this is good for a 95%-ready review, can you have a look?

What's next:

  • add a better representation for * -- i've just realized looking at the screenshot it's still using the X (cause i was lazy yesterday)
  • add documentation

@willmcgugan
Copy link
Collaborator

Looks amazing, but you may have gone a little over and above the requirements there! We were looking for a widget that does digits, i.e. 0-9, with a few additional symbols like decimal point to display numbers.

You've been very creative with regards to letters, but some just don't work to well with the very limited number of block characters. They are also limited to the Western alphabet, which is a problem for a framework designed for a global audience. And it would be nigh on impossible to represent all European alphabets, never mind CJK characters.

Sadly, for these reasons I don't this belongs in the core library. However it is undeniable cool so maybe you could publish it as an external packages on PyPI? Perhaps textual-led-display ?

@rodrigogiraoserrao
Copy link
Contributor

Just to clarify, we're still interested in the core, something like 01234567890.+-,X^, and we're happy to merge those in.

Will just doesn't want all of your remaining work to go to waste, and that's why he suggested you create a package with all of your characters.

@eliasdorneles
Copy link
Author

Right, I get that, indeed I got a bit carried over with the excitement 😂

I believe it makes sense actually for this to be a separate package, I think doing this properly would mean to accept multiple "fonts", like figlet does, but with better fonts because we can use Unicode blocks.
I don't know if I'll have time to work on that in the future, though.

Okay, so I will make a new PR with a widget for the core, as you're going for arithmetic operators, I propose the widget in core could have these characters: 01234567890.+-,XYZ^*/.

Here's what they look like:

image

image

What do you think? Anything to add or remove there? @rodrigogiraoserrao @willmcgugan

@eliasdorneles eliasdorneles mentioned this pull request Jul 23, 2023
3 tasks
@eliasdorneles
Copy link
Author

Closing this in favor of: #2995

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

Successfully merging this pull request may close these issues.

3 participants