"""A half-block wordmark font for the header hero. Every shipped catalogue draws its brand the same way: four-column capitals, six pixels tall, emitted as three rows of half blocks (``▀``/``▄``/``█``) — the same shape as the original SomaFM logo. The header paints every wordmark with the app's active palette gradient, so catalogues differ only in the word they spell; the font lives here and each provider's ``hero.py`` is one line of data. Glyphs are 6x4 bitmaps (``M`` is 6x5). Two pixel rows become one text row, so a wordmark is always three rows tall and the header keeps a fixed height. """ from __future__ import annotations #: 6-row bitmap per capital; all rows of one glyph are the same width. GLYPHS: dict[str, tuple[str, ...]] = { "A": (".##.", "#..#", "####", "#..#", "#..#", "#..#"), "B": ("###.", "#..#", "###.", "#..#", "#..#", "###."), "C": (".##.", "#..#", "#...", "#...", "#..#", ".##."), "D": ("###.", "#..#", "#..#", "#..#", "#..#", "###."), "E": ("####", "#...", "###.", "#...", "#...", "####"), "F": ("####", "#...", "###.", "#...", "#...", "#..."), "G": (".##.", "#..#", "#...", "#.##", "#..#", ".##."), "H": ("#..#", "#..#", "####", "#..#", "#..#", "#..#"), "I": ("###", ".#.", ".#.", ".#.", ".#.", "###"), "K": ("#..#", "#.#.", "##..", "##..", "#.#.", "#..#"), "L": ("#...", "#...", "#...", "#...", "#...", "####"), # 5 wide on purpose: the M is the odd one out in the original wordmark. "M": ("#...#", "##.##", "#.#.#", "#.#.#", "#...#", "#...#"), "N": ("#..#", "##.#", "##.#", "#.##", "#..#", "#..#"), "O": (".##.", "#..#", "#..#", "#..#", "#..#", ".##."), "P": ("###.", "#..#", "###.", "#...", "#...", "#..."), "R": ("###.", "#..#", "###.", "#.#.", "#..#", "#..#"), "S": (".###", "#...", "###.", "...#", "...#", "###."), "T": ("###", ".#.", ".#.", ".#.", ".#.", ".#."), "U": ("#..#", "#..#", "#..#", "#..#", "#..#", ".##."), "V": ("#..#", "#..#", "#..#", "#..#", ".##.", ".##."), "W": ("#...#", "#...#", "#.#.#", "#.#.#", "##.##", "#...#"), "Y": ("#..#", "#..#", ".##.", "..#.", "..#.", "..#."), } ROWS = 3 _GAP = " " def _cell(top: str, bottom: str) -> str: if top == "#" and bottom == "#": return "█" if top == "#": return "▀" if bottom == "#": return "▄" return " " def _glyph_rows(char: str) -> tuple[str, ...]: bitmap = GLYPHS.get(char) if bitmap is None: raise KeyError(f"no wordmark glyph for {char!r}") return tuple( "".join(_cell(bitmap[row * 2][col], bitmap[row * 2 + 1][col]) for col in range(len(bitmap[0]))) for row in range(ROWS) ) def render(text: str) -> tuple[str, ...]: """Spell ``text`` as three rows of half blocks.""" glyphs = [_glyph_rows(char.upper()) for char in text] rows: list[str] = [] for row in range(ROWS): rows.append(_GAP.join(glyph[row] for glyph in glyphs).rstrip()) return tuple(rows)