Big Text (mit urwid)

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Benutzeravatar
snafu
User
Beiträge: 6481
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hey, ich habe mal das BigText Widget von urwid "missbraucht", um dieses Feature für die Terminal-Ausgabe zu nutzen. Mein Code kommt ohne den MainLoop aus, weil er direkt auf urwids render()-Methode arbeitet. Im Endeffekt könnte man sich die relevanten Teile von urwid auch einfach rauskopieren, denn es wird nur ein relativ kleiner Teil von urwid genutzt und curses (vermutlich) gar nicht. Aber da halte ich wohl besser Rücksprache mit dem Projektbetreuer, falls ich das wirklich weiterverfolge.

Geplante Erweiterungen wären eine vereinfachte Schriftauswahl (basierend auf Größe und Stil), sowie Kommandozeilen-Argumente. Außerdem Support für Buchstaben in allen Schriften (wobei sich meine Designer-Fähigkeiten in Grenzen halten) und für Umlaute bzw Nicht-ASCII Zeichen (da bin ich definitiv raus).

Hier auf jeden Fall mein bisheriger Stand:

Code: Alles auswählen

#!/usr/bin/env python3
import urwid

class FontStore:
    def __init__(self, utf8_mode=None):
        self._fonts = {
            self._normalize(font_name): font_class()
            for font_name, font_class in urwid.get_all_fonts()
        }
        if utf8_mode is None:
            self.utf8_mode = urwid.get_encoding_mode() == "utf8"
        else:
            self.utf8_mode = utf8_mode

    @staticmethod
    def _normalize(font_name):
        return font_name.capitalize()

    def _is_available(self, font):
        if self.utf8_mode:
            # All fonts are allowed
            return True
        return not font.utf8_required

    @property
    def fonts(self):
        return {
            name: font for name, font in self._fonts.items()
            if self._is_available(font)
        }

    @property
    def font_names(self):
        return sorted(self.fonts.keys())

    def get_font(self, font_name):
        normalized = self._normalize(font_name)
        if normalized not in self._fonts:
            raise ValueError(f"Unknown font: {font_name}")
        font = self._fonts[normalized]
        if not self._is_available(font):
            raise ValueError(
                f"Font {font_name!r} only available in UTF-8 mode"
            )
        return font


class Renderer:
    def __init__(self, font_store=None, encoding=None):
        self.font_store = font_store or FontStore()
        self.encoding = encoding or urwid.get_encoding_mode()

    def get_unsupported(self, text, font_name):
        font = self.font_store.get_font(font_name)
        allowed_chars = set(font.characters())
        return list(set(text) - allowed_chars)

    def _check(self, text, font_name):
        unsupported = self.get_unsupported(text, font_name)
        if len(unsupported) > 0:
            raise ValueError(
                f"Cannot render these characters: {unsupported}"
            )

    def render(self, text, font_name, check_chars=True):
        if check_chars:
            self._check(text, font_name)
        font = self.font_store.get_font(font_name)
        bigtext = urwid.BigText(text, font)
        text = b"\n".join(bigtext.render(()).text)
        return text.decode(self.encoding)


def main():
    r = Renderer()
    print("Available fonts:", r.font_store.font_names, sep="\n")
    print(r.render("Hello World", "Thin 6x6"))
    # This should fail
    # print(r.render("65 mph", "Thin 3x3"))


if __name__ == "__main__":
    main()
Benutzeravatar
snafu
User
Beiträge: 6481
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was mir schon selber aufgefallen ist: Es ist etwas strange, dass man font_store.get_font(), aber auch font_store.fonts.get() benutzen kann. Zumal letzteres ja ein property ist und immer wieder neu erstellt wird (also suboptimal ist). Ich habe fonts() daher rausgeschmissen und die font_names()-Methode entsprechend angepasst. Das bisschen an Änderung lade ich aber nicht extra hoch.
Benutzeravatar
__blackjack__
User
Beiträge: 10669
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

„With the neutron bomb, which destroys life but not property, capitalism has found the weapon of its dreams.” — Edward Abbey
Benutzeravatar
snafu
User
Beiträge: 6481
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nein, kannte ich noch nicht. Mich hatte schon gewundert, dass es bisher nichts aus dem Bereich gibt. Ich habe aber nur oberflächlich nach "bigtext" gesucht. So ein bisschen war es auch, um mal tiefer in urwid einzusteigen. pyfiglet ist in Sachen Texte rendern jedenfalls deutlich ausgereifter.
Antworten