"""5×7 bitmap text for LED matrices.""" from __future__ import annotations from typing import Tuple from leds.array_config import MATRIX_HEIGHT, MATRIX_WIDTH, matrix_pixel_index RGB = Tuple[int, int, int] # Each letter: 7 rows, 5 LSBs = columns (bit 4 = left). _FONT: dict[str, tuple[int, ...]] = { " ": (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), "A": (0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11), "B": (0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E), "C": (0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E), "D": (0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E), "E": (0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F), "F": (0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10), "G": (0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0E), "H": (0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11), "I": (0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E), "J": (0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C), "K": (0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11), "L": (0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F), "M": (0x11, 0x1B, 0x15, 0x11, 0x11, 0x11, 0x11), "N": (0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11), "O": (0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E), "P": (0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10), "Q": (0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D), "R": (0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11), "S": (0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E), "T": (0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04), "U": (0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E), "V": (0x11, 0x11, 0x11, 0x11, 0x0A, 0x0A, 0x04), "W": (0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11), "X": (0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11), "Y": (0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04), "Z": (0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F), "0": (0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E), "1": (0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E), "2": (0x0E, 0x11, 0x01, 0x06, 0x08, 0x10, 0x1F), "3": (0x1F, 0x02, 0x04, 0x06, 0x01, 0x11, 0x0E), "4": (0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02), "5": (0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E), "6": (0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E), "7": (0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08), "8": (0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E), "9": (0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C), } CHAR_WIDTH = 5 CHAR_HEIGHT = 7 CHAR_SPACING = 1 def text_width(text: str, spacing: int = CHAR_SPACING) -> int: text = text.upper() if not text: return 0 return len(text) * CHAR_WIDTH + (len(text) - 1) * spacing def _set(surface, x: int, y: int, color: RGB) -> None: if hasattr(surface, "width") and hasattr(surface, "height"): if 0 <= x < surface.width and 0 <= y < surface.height: surface[x, y] = color else: w = getattr(surface, "width", MATRIX_WIDTH) idx = matrix_pixel_index(x, y, w) if 0 <= idx < len(surface): surface[idx] = color def draw_char( surface, ch: str, x: int, y: int, color: RGB, *, scale: int = 1, ) -> None: glyph = _FONT.get(ch.upper(), _FONT[" "]) for row, bits in enumerate(glyph): for col in range(CHAR_WIDTH): if bits & (1 << (CHAR_WIDTH - 1 - col)): for sy in range(scale): for sx in range(scale): _set(surface, x + col * scale + sx, y + row * scale + sy, color) def draw_text( surface, text: str, x: int, y: int, color: RGB, *, scale: int = 1, spacing: int = CHAR_SPACING, ) -> None: cursor = x step = (CHAR_WIDTH + spacing) * scale for ch in text.upper(): draw_char(surface, ch, cursor, y, color, scale=scale) cursor += step def draw_text_centered( surface, text: str, color: RGB, *, scale: int = 1, spacing: int = CHAR_SPACING, ) -> None: w = getattr(surface, "width", MATRIX_WIDTH) h = getattr(surface, "height", MATRIX_HEIGHT) tw = text_width(text, spacing) * scale th = CHAR_HEIGHT * scale x = max(0, (w - tw) // 2) y = max(0, (h - th) // 2) draw_text(surface, text, x, y, color, scale=scale, spacing=spacing)