diff --git a/tools/station/display/render.py b/tools/station/display/render.py index 7323add..dc7ecd4 100644 --- a/tools/station/display/render.py +++ b/tools/station/display/render.py @@ -194,11 +194,24 @@ ARMED_DETAIL_PREFIX = "Freigabe: " # "Lampe: sofort ins WLAN" sagt ihm genau das, was er wissen muss, bevor er einschaltet. # Der gefaehrliche Zustand steht in Grossbuchstaben - er ist der, den man uebersehen soll # und darf. +# Die Zeile muss UNGEKUERZT passen, und zwar auch mit einer breiteren Schrift als der +# hier gerade installierten: am Geraet (DejaVu) kam die alte, laengere Fassung als +# "Lampe -> Onboarding-AP (ohne WLA..." an - der Zusatz in der Klammer, also gerade die +# Aussage, fiel weg. Auf dem Mac des Entwicklers (Arial, schmaler) passte dieselbe Zeile +# mit 246,0 von 246 px haarscharf; deshalb hat es niemand bemerkt. Breitenbudget siehe +# test_imageset_footer_fits_the_panel_with_room_for_a_wider_font. IMAGESET_LABELS = { - "ohne-wlan": "Lampe -> Onboarding-AP (ohne WLAN-Daten)", - "mit-wlan": "Lampe -> SOFORT INS EIGENE WLAN", + "ohne-wlan": "ohne WLAN-Daten (Onboarding-AP)", + "mit-wlan": "MIT WLAN-Daten (eigenes Netz)", +} +# Fehlt das Verzeichnis des gewaehlten Satzes, ERSETZT die Warnung die Zeile, statt sie +# zu verlaengern. Als angehaengtes Suffix (" - SATZ FEHLT", bis 2026-09-15) war sie in +# BEIDEN Richtungen und in beiden Schriften ausserhalb der Panelbreite - die einzige +# Zeile, die sagt, dass die Station gar nichts ausliefern kann, war damit nie zu sehen. +IMAGESET_MISSING_LABELS = { + "ohne-wlan": "SATZ FEHLT: ohne WLAN-Daten", + "mit-wlan": "SATZ FEHLT: MIT WLAN-Daten", } -IMAGESET_MISSING_SUFFIX = " - SATZ FEHLT" # Der Abschlussbildschirm: was auf dem Panel stehen bleibt, wenn der Pi heruntergefaehrt # oder neu gestartet wird. E-Paper ist bistabil - das zuletzt gezeichnete Bild bleibt fuer @@ -420,7 +433,7 @@ def _imageset_blocks(state: dict) -> list[tuple[str, str]]: if not label: return [] if state.get("imageset_ok") is False: - label += IMAGESET_MISSING_SUFFIX + label = IMAGESET_MISSING_LABELS[name] return [(label, ROLE_FOOTER)] diff --git a/tools/station/tests/test_render.py b/tools/station/tests/test_render.py index 2b43f0e..4a98913 100644 --- a/tools/station/tests/test_render.py +++ b/tools/station/tests/test_render.py @@ -2064,3 +2064,49 @@ def test_missing_pillow_logs_exactly_one_line_and_exits_zero(argv, monkeypatch, assert len(caplog.records) == 1, \ f"erwartet genau eine Protokollzeile, bekommen: {[r.getMessage() for r in caplog.records]}" assert "PIL" in caplog.records[0].getMessage() + + +# --- Fusszeile des Bildsatz-Umschalters (Geraetetermin 2026-09-15) ------------------ +# +# Am Geraet kam die Zeile gekuerzt an: "Lampe -> Onboarding-AP (ohne WLA...". Ausgerechnet +# die Klammer, die den Zustand benennt, fiel weg - und mit dem Zusatz " - SATZ FEHLT" war +# die WARNUNG, dass der gewaehlte Satz gar nicht auf dem Pi liegt, in beiden Richtungen +# unsichtbar (367,5 px bzw. 306 px bei 246 px Platz). +# +# Warum die Testsuite das nie bemerkt hat: _load_font() nimmt den ersten Pfad, der sich +# oeffnen laesst. Auf dem Pi ist das DejaVu Sans Bold, auf dem Mac des Entwicklers faellt +# die Kette bis "Arial Bold.ttf" durch - und Arial baut schmaler. Dieselbe Zeile misst +# dort 246,0 von 246 px (haarscharf drin), auf dem Pi 283,5 px. Das Layout war damit auf +# die Schrift der ENTWICKLUNGSMASCHINE ausgelegt, nicht auf die des Zielgeraets. +# +# Dieser Test misst deshalb mit einer ausdruecklichen Marge: die Zusage lautet nicht "es +# passt mit der hier zufaellig installierten Schrift", sondern "es passt auch mit einer +# spuerbar breiteren". 25 % decken den gemessenen Abstand Arial -> DejaVu (+15 %) mit +# Reserve ab. +FOOTER_WIDTH_SAFETY = 1.25 + + +def _footer_width_px(text: str) -> float: + from PIL import Image, ImageDraw, ImageFont + draw = ImageDraw.Draw(Image.new("1", (render.PANEL_WIDTH_PX, + render.PANEL_HEIGHT_PX), 255)) + font = render._load_font(ImageFont, render.FOOTER_FONT_PX, bold=True) + return draw.textlength(text, font=font) + + +@pytest.mark.parametrize("name", sorted(render.IMAGESET_LABELS)) +@pytest.mark.parametrize("missing", [False, True]) +def test_imageset_footer_fits_the_panel_with_room_for_a_wider_font(name, missing): + """Jede Fusszeile des Umschalters - beide Saetze, mit und ohne Fehlt-Warnung - muss + ungekuerzt auf das Panel passen, auch wenn die Schrift des Zielgeraets breiter baut + als die hier installierte. Der Fehlt-Fall ist der wichtigere der vier: er sagt, dass + der GEWAEHLTE Bildsatz nicht auf dem Pi liegt, und genau der war unsichtbar.""" + text, = (t for t, role in render._imageset_blocks( + {"imageset": name, "imageset_ok": not missing}) if role == render.ROLE_FOOTER) + max_width_px = render.PANEL_WIDTH_PX - 2 * render.TEXT_MARGIN_PX + width_px = _footer_width_px(text) + + assert width_px * FOOTER_WIDTH_SAFETY <= max_width_px, ( + "Fusszeile {!r} misst {:.1f} px; mit {:.0f} %% Reserve fuer eine breitere " + "Schrift bleiben nur {:.1f} px Platz".format( + text, width_px, (FOOTER_WIDTH_SAFETY - 1) * 100, max_width_px))