Big Text (mit urwid)
Verfasst: Sonntag 12. Juni 2022, 07:07
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:
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()