Compare commits

..
Author SHA1 Message Date
raw-designsandClaude Opus 5 b3b96362c3 feat(P4): Eigener Menüpunkt "Darstellung", größere Uhr im Standby (1.9.6)
- Der Darstellungsblock wandert aus build_info() in ein eigenes build_display()
  mit neuer Seite PG_DISPLAY. Die Info-Seite zeigt nur noch Firmware-Stände und
  Verbindungsdaten.
- clock_font() liefert für WS_PANEL_7H jetzt 180/270/360 statt 120/180/240. Für
  JC_PANEL_43 bleiben die alten Stufen - 360 px passen nicht auf 480x480.
- Neue Fonts lv_font_clock_270/_360 (Maven Pro Regular, bpp 4, Range
  32,45,0x30-0x3A). bpp 3 scheidet aus: lv_font_conv erlaubt das nur mit
  Kompression, und die kostet beim Zeichnen genau das, was gerade eingespart wird.
- Alle fünf Uhr-Fonts sind deklariert; der Linker verwirft die je nach Panel
  ungenutzten. Netto wächst die WS-Firmware um 196 KB.

Beide Panel-Varianten mit arduino-cli gegengebaut (PartitionScheme=custom,
passend zur partitions.csv mit zwei 6,5-MB-Slots).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
2026-09-03 09:23:50 +02:00
thomas 14f1a4789d Merge pull request 'perf(P4): Auch feste Höhen - LVGL markiert sonst das Layout als dirty (1.9.5)' (#74) from perf/feste-hoehen-und-nachweis into main 2026-09-03 07:25:04 +02:00
raw-designsandClaude Opus 5 326af4288a perf(P4): Auch feste Höhen - LVGL markiert sonst das Layout als dirty (1.9.5)
Die festen Breiten aus 1.9.4 haben nicht gereicht. lv_label_set_text ruft
lv_obj_refresh_self_size(); ist eines der beiden Maße LV_SIZE_CONTENT, gilt
das Parent-Layout als dirty und der Container wird komplett invalidiert.

- tempField(): big und setp bekommen zusätzlich eine feste Höhe aus
  lv_font_get_line_height().
- infoCell(): val ebenso, mit Platz für zwei Zeilen.
- g_clock: feste Breite/Höhe, rechtsbündig. Erklärt den Bereich
  "x 6..57, y 2..41" (Menü-Knopf), der bei jedem Minutenwechsel durch das
  Header-Relayout mit invalidiert wurde.

Zusätzlich eine gezielte Diagnose: LV_EVENT_INVALIDATE_AREA auf g_content
und der Dashboard-Seite meldet, wenn ein ganzer Container invalidiert wird -
damit ist "einzelnes Label" von "kompletter Bereich" zu unterscheiden.

Beide Panel-Varianten mit arduino-cli gegengebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 03:10:40 +02:00
thomas 2e8651bc00 Merge pull request 'perf(P4): Feste Breiten für Anzeigewerte - kein Neulayout mehr (1.9.4)' (#73) from perf/feste-breiten-kein-neulayout into main 2026-09-03 02:56:24 +02:00
raw-designsandClaude Opus 5 b13e5fdaf1 perf(P4): Feste Breiten für Anzeigewerte - kein Neulayout mehr (1.9.4)
Die Koordinaten haben den Verursacher benannt: Der invalidierte Bereich war
"x 0..1279, y 44..719" - der komplette Content-Container, bei jeder
Zustandsmeldung.

Grund: Die Wert-Labels hatten LV_SIZE_CONTENT. Ändert sich ihre Breite mit
dem Inhalt (92,4 °C -> 100,1 °C), löst LVGL ein Flex-Relayout der ganzen
Seite aus und invalidiert sie komplett. Change-checked Text allein reicht
also nicht - der Text darf beim Ändern auch die Breite nicht ändern.

tempField() und infoCell() setzen die Wert-Labels jetzt auf LV_PCT(100) mit
zentriertem Text. Optisch identisch, da die Werte ohnehin mittig standen.

Beide Panel-Varianten mit arduino-cli gegengebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 02:56:05 +02:00
thomas 671a6696ce Merge pull request 'fix(P4): Menüvorhang wieder durchscheinend, weitere Invalidierung entfernt (1.9.3)' (#72) from fix/menuevorhang-und-weitere-invalidierung into main 2026-09-03 02:36:48 +02:00
5 changed files with 38432 additions and 5 deletions
+35
View File
@@ -1,3 +1,38 @@
Version 1.9.6:
- Die Darstellungseinstellungen haben einen eigenen Menüpunkt „Darstellung" bekommen. Sie
standen bisher oben auf der Info-Seite, zwischen Sachen, mit denen sie nichts zu tun
haben. Die Info-Seite zeigt jetzt nur noch Firmware-Stände und Verbindungsdaten.
- Die Uhr im Standby ist auf dem 7-Zoll-Panel deutlich größer geworden: Die drei Stufen
liegen jetzt bei 180, 270 und 360 Pixeln statt bei 120, 180 und 240. Auf dem 4,3-Zoll-
Panel bleiben die bisherigen Stufen, dort passen größere schlicht nicht auf den Schirm.
Version 1.9.5:
- Die festen Breiten aus 1.9.4 haben nicht gereicht: Auch die HÖHE muss festliegen. LVGL
prüft beim Setzen eines Textes, ob sich die Eigengröße der Beschriftung geändert haben
könnte - ist eines der beiden Maße frei, gilt das Layout des Elternteils als neu zu
berechnen, und das macht die ganze Seite ungültig. Temperaturwerte, Sollwerte, die Werte
der unteren Zeile und die Uhrzeit in der Kopfleiste haben jetzt feste Maße in beide
Richtungen.
- Die Uhrzeit hatte denselben Effekt in der Kopfleiste: Beim Wechsel der Minute wurde die
Leiste samt Menü-Knopf neu berechnet. Das erklärt den Bereich „x 6..57, y 2..41", der in
fast jedem Durchgang auftauchte.
- Zusätzlich meldet die Firmware jetzt, wenn der Inhaltsbereich oder die Dashboard-Seite als
Ganzes ungültig gemacht wird. Damit ist zu unterscheiden, ob eine einzelne Beschriftung
den Bildaufbau auslöst oder gleich der komplette Bereich - zwei verschiedene Ursachen mit
verschiedenen Gegenmitteln.
Version 1.9.4:
- Die Messung mit Koordinaten hat den Verursacher benannt: Der ungültige Bereich war
„x 0..1279, y 44..719" - also der gesamte Inhalt unterhalb der Kopfleiste, bei jeder
Zustandsmeldung.
- Grund: Die Anzeigewerte hatten keine feste Breite. Wächst oder schrumpft eine Beschriftung
mit ihrem Inhalt - etwa von „92,4 °C" auf „100,1 °C" -, rechnet LVGL das Layout der
gesamten Seite neu und macht sie dabei komplett ungültig. Es genügt also nicht, den Text
nur bei echter Änderung zu setzen; er darf beim Ändern auch die Breite nicht verändern.
- Temperaturwerte, Sollwerte und die Werte der unteren Zeile haben jetzt eine feste Breite
mit zentriertem Text. Sichtbar ändert sich dadurch nichts - die Werte standen ohnehin
mittig.
Version 1.9.3:
- Fehlerbehebung: Bei geöffnetem Menü war der Seiteninhalt dahinter verschwunden. Der
Vorhang des Menüs war in 1.8.7 deckend gemacht worden, um Zeichenlast zu sparen - dabei
+3 -1
View File
@@ -571,7 +571,9 @@
LV_FONT_DECLARE(lv_font_maven_pro_bold_140) \
LV_FONT_DECLARE(lv_font_clock_120) \
LV_FONT_DECLARE(lv_font_clock_180) \
LV_FONT_DECLARE(lv_font_clock_240)
LV_FONT_DECLARE(lv_font_clock_240) \
LV_FONT_DECLARE(lv_font_clock_270) \
LV_FONT_DECLARE(lv_font_clock_360)
/*Always set a default font*/
#define LV_FONT_DEFAULT &lv_font_maven_pro_14
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+52 -4
View File
@@ -127,8 +127,8 @@ static lv_obj_t* g_otaStatus = nullptr;
static lv_obj_t* g_otaBytes = nullptr;
// Navigation
enum { PG_DASH = 0, PG_CHART, PG_STATS, PG_TEMP, PG_BREW, PG_COLDEX, PG_SERVICE, PG_PROFILE, PG_LIGHT, PG_WIFI, PG_INFO, PG_COUNT };
static const char* PAGE_NAMES[PG_COUNT] = { "Dashboard", "Verlauf", "Statistik", "Temperatur", "Brew-Control", "Cold Extraction", "Reinigung/Wartung", "Profile", "Licht", "WiFi", "Info" };
enum { PG_DASH = 0, PG_CHART, PG_STATS, PG_TEMP, PG_BREW, PG_COLDEX, PG_SERVICE, PG_PROFILE, PG_LIGHT, PG_WIFI, PG_DISPLAY, PG_INFO, PG_COUNT };
static const char* PAGE_NAMES[PG_COUNT] = { "Dashboard", "Verlauf", "Statistik", "Temperatur", "Brew-Control", "Cold Extraction", "Reinigung/Wartung", "Profile", "Licht", "WiFi", "Darstellung", "Info" };
static lv_obj_t* g_content = nullptr;
static lv_obj_t* g_pages[PG_COUNT] = { nullptr };
static lv_obj_t* g_drawer = nullptr;
@@ -700,9 +700,17 @@ static lv_obj_t* g_clockSizeBtn[3] = {};
static const lv_font_t* clock_font() {
switch (g_clockSize) {
#if JC_PANEL_TYPE == WS_PANEL_7H
// 7 Zoll, 1280x720: Hier war selbst die groesste Stufe noch zu klein.
case UHR_KLEIN: return &lv_font_clock_180;
case UHR_MITTEL: return &lv_font_clock_270;
default: return &lv_font_clock_360;
#else
// 4,3 Zoll, 480x480: Groessere Stufen passen schlicht nicht auf das Panel.
case UHR_KLEIN: return &lv_font_clock_120;
case UHR_MITTEL: return &lv_font_clock_180;
default: return &lv_font_clock_240;
#endif
}
}
@@ -1056,6 +1064,18 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
lv_label_set_text(*big, "--.-");
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
lv_obj_set_style_text_font(*big, valueFont, 0);
// Feste Breite, Text zentriert. Waechst oder schrumpft eine Beschriftung mit ihrem
// Inhalt - etwa von "92,4 °C" auf "100,1 °C" -, rechnet LVGL das Flex-Layout der
// gesamten Seite neu und macht sie damit komplett ungueltig. Genau das war im
// Messprotokoll als "x 0..1279, y 44..719" zu sehen: der ganze Inhaltsbereich, bei
// jeder Zustandsmeldung. Mit fester Breite bleibt nur die Beschriftung selbst ungueltig.
lv_obj_set_width(*big, LV_PCT(100));
lv_obj_set_style_text_align(*big, LV_TEXT_ALIGN_CENTER, 0);
// Auch die HOEHE muss fest sein. LVGL prueft beim Setzen eines Textes, ob sich die
// Eigengroesse der Beschriftung geaendert haben koennte - ist eines der beiden Masse
// frei, gilt das Layout des Elternteils als neu zu berechnen, und das macht die ganze
// Seite ungueltig. Erst mit festen Massen bleibt nur die Beschriftung selbst ungueltig.
lv_obj_set_height(*big, lv_font_get_line_height(valueFont) + 6);
// Grosse Zahlen etwas enger setzen. Bei dieser Groesse wirken die Werksabstaende
// auseinandergezogen; ein paar Pixel weniger binden die Ziffern zu einer Zahl zusammen.
if (valueFont == &lv_font_maven_pro_bold_140) lv_obj_set_style_text_letter_space(*big, -3, 0);
@@ -1065,6 +1085,9 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
lv_label_set_text(*setp, "Soll --.-");
lv_obj_set_style_text_color(*setp, COL_TEXT_DIM, 0);
lv_obj_set_style_text_font(*setp, font_text(), 0);
lv_obj_set_width(*setp, LV_PCT(100));
lv_obj_set_style_text_align(*setp, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_set_height(*setp, lv_font_get_line_height(font_text()) + 6);
*bar = lv_bar_create(c);
lv_obj_set_size(*bar, LV_PCT(92), 8);
@@ -1210,6 +1233,10 @@ static lv_obj_t* infoCell(lv_obj_t* parent, const char* title, lv_obj_t** val, l
lv_obj_set_style_text_color(*val, COL_TEXT, 0);
lv_obj_set_style_text_font(*val, font_title(), 0);
lv_obj_set_style_text_align(*val, LV_TEXT_ALIGN_CENTER, 0); // fuer mehrzeilige Werte
// Feste Masse in BEIDE Richtungen - siehe die ausfuehrliche Begruendung in tempField.
// Zwei Zeilen Platz, weil manche Werte zweizeilig sind ("32,4 g / 36,0 g").
lv_obj_set_width(*val, LV_PCT(100));
lv_obj_set_height(*val, lv_font_get_line_height(font_title()) * 2 + 6);
return card;
}
// Tipp auf die Statuszeile: Wartung -> Serviceseite, Reinigung -> Sub-Screen,
@@ -3081,8 +3108,10 @@ static void brew_live_sw_cb(lv_event_t* e) {
{ Preferences prefs; prefs.begin("ui", false); prefs.putBool("brewlive", g_brewLiveEnabled); prefs.end(); }
if (!g_brewLiveEnabled) brew_live_hide(); // laeuft gerade ein Bezug: sofort ausblenden
}
static void build_info(lv_obj_t* p) {
section_title(p, "Darstellung");
// Eigener Menuepunkt "Darstellung". Die Einstellungen sassen frueher oben auf der
// Info-Seite; dort standen sie zwischen Firmware-Staenden und Verbindungsdaten,
// mit denen sie nichts zu tun haben.
static void build_display(lv_obj_t* p) {
lv_obj_t* dcard = th_card(p);
lv_obj_set_width(dcard, LV_PCT(100));
lv_obj_set_height(dcard, LV_SIZE_CONTENT);
@@ -3135,6 +3164,9 @@ static void build_info(lv_obj_t* p) {
sw_set(swBrewLive, g_brewLiveEnabled);
lv_obj_add_event_cb(swBrewLive, brew_live_sw_cb, LV_EVENT_VALUE_CHANGED, nullptr);
}
static void build_info(lv_obj_t* p) {
section_title(p, "Firmware-Stände & Verbindung");
lv_obj_t* card = th_card(p);
@@ -3533,6 +3565,14 @@ static void refr_ready_cb(lv_event_t*) {
(int)g_refrArea[i].y1, (int)g_refrArea[i].y2);
}
// Meldet, wenn ein ganzer Container ungueltig gemacht wird. Damit laesst sich unterscheiden,
// ob eine einzelne Beschriftung den Bildaufbau ausloest oder ob gleich der komplette
// Inhaltsbereich neu gezeichnet werden soll - zwei verschiedene Ursachen.
static void inval_watch_cb(lv_event_t* e) {
const char* name = (const char*)lv_event_get_user_data(e);
esp_rom_printf("[UI] %s wird komplett ungueltig\n", name);
}
static void refr_monitor_install() {
lv_display_t* d = lv_display_get_default();
if (!d) return;
@@ -3650,6 +3690,11 @@ void ui_init(ProtocolClient* client) {
lv_obj_set_style_text_color(g_clock, COL_TEXT, 0);
lv_obj_set_style_pad_right(g_clock, 10, 0);
lv_obj_set_style_text_font(g_clock, font_text(), 0);
// Feste Masse, sonst rechnet LVGL beim Wechsel der Minute das Layout der Kopfleiste neu
// und macht sie samt Menue-Knopf ungueltig (siehe tempField).
lv_obj_set_width(g_clock, 130);
lv_obj_set_height(g_clock, lv_font_get_line_height(font_text()) + 4);
lv_obj_set_style_text_align(g_clock, LV_TEXT_ALIGN_RIGHT, 0);
g_wifiIcon = lv_label_create(header);
lv_label_set_text(g_wifiIcon, LV_SYMBOL_WIFI);
@@ -3677,6 +3722,7 @@ void ui_init(ProtocolClient* client) {
g_pages[PG_SERVICE] = make_page(g_content); build_service(g_pages[PG_SERVICE]);
g_pages[PG_WIFI] = make_page(g_content); build_wifi(g_pages[PG_WIFI]);
g_pages[PG_PROFILE] = make_page(g_content); build_profiles(g_pages[PG_PROFILE]);
g_pages[PG_DISPLAY] = make_page(g_content); build_display(g_pages[PG_DISPLAY]);
g_pages[PG_INFO] = make_page(g_content); build_info(g_pages[PG_INFO]);
// --- Schublade (Scrim + Menue-Panel) ---
@@ -3938,6 +3984,8 @@ void ui_init(ProtocolClient* client) {
if (g_client) g_client->sendListProfiles();
refr_monitor_install();
if (g_content) lv_obj_add_event_cb(g_content, inval_watch_cb, LV_EVENT_INVALIDATE_AREA, (void*)"Inhaltsbereich");
if (g_pages[PG_DASH]) lv_obj_add_event_cb(g_pages[PG_DASH], inval_watch_cb, LV_EVENT_INVALIDATE_AREA, (void*)"Dashboard-Seite");
g_uiReady = true;
}