v2.3: Twinkling star animation extended to all menus and splash screen, WiFi submenu removed

This commit is contained in:
Eiswolf-BG
2026-08-05 05:49:51 +02:00
parent d89024e419
commit 59aa5af1b2
16 changed files with 129 additions and 29 deletions

View File

@@ -1,6 +1,7 @@
#include "airline_filter_screen.h"
#include "airline_filter.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -25,6 +26,7 @@ namespace {
}
String runLetterKeypad(TFT_eSPI& tft) {
MenuStars::reset();
constexpr const char* ROW1 = "QWERTYUIOP";
constexpr const char* ROW2 = "ASDFGHJKL";
constexpr const char* ROW3 = "ZXCVBNM";
@@ -85,7 +87,7 @@ namespace {
while (!done) {
TouchInput::Point tap;
if (!TouchInput::wasTapped(tap)) { delay(20); continue; }
if (!TouchInput::wasTapped(tap)) { MenuStars::update(tft); delay(20); continue; }
bool handled = false;
for (uint8_t i = 0; i < 10 && !handled; i++) {
@@ -125,6 +127,7 @@ void run(TFT_eSPI& tft) {
constexpr int16_t REMOVE_BTN_W = 60;
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -172,6 +175,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

View File

@@ -1,5 +1,6 @@
#include "calibration_screen.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -21,10 +22,11 @@ namespace {
tft.fillCircle(x, y, 3, TFT_WHITE);
}
RawAvg waitForTap() {
RawAvg waitForTap(TFT_eSPI& tft) {
RawAvg avg;
while (!TouchInput::rawPoint().touched) {
MenuStars::update(tft);
delay(10);
}
@@ -73,7 +75,8 @@ void run(TFT_eSPI& tft) {
tft.setTextDatum(TL_DATUM);
drawTarget(tft, targets[i].x, targets[i].y);
samples[i] = waitForTap();
MenuStars::reset();
samples[i] = waitForTap(tft);
}
int16_t xmin = (samples[0].avgX() + samples[3].avgX()) / 2;

View File

@@ -1,6 +1,7 @@
#include "first_run_language_screen.h"
#include "settings_store.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "i18n.h"
#include "config.h"
@@ -45,9 +46,10 @@ void run(TFT_eSPI& tft) {
drawButton(tft, langRects[i], I18n::languageName(i));
}
MenuStars::reset();
while (true) {
TouchInput::Point tap;
if (!TouchInput::wasTapped(tap)) { delay(20); continue; }
if (!TouchInput::wasTapped(tap)) { MenuStars::update(tft); delay(20); continue; }
for (uint8_t i = 0; i < I18n::LANG_COUNT; i++) {
if (langRects[i].contains(tap.x, tap.y)) {

View File

@@ -1,6 +1,7 @@
#include "language_screen.h"
#include "settings_store.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "i18n.h"
#include "config.h"
@@ -37,6 +38,7 @@ namespace {
void run(TFT_eSPI& tft) {
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -57,6 +59,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

View File

@@ -1,6 +1,7 @@
#include "location_presets_screen.h"
#include "location_presets.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -28,6 +29,7 @@ namespace {
}
String runNumericKeypad(TFT_eSPI& tft, const String& title) {
MenuStars::reset();
char buf[16] = {0};
uint8_t len = 0;
@@ -79,7 +81,7 @@ namespace {
while (!done) {
TouchInput::Point tap;
if (!TouchInput::wasTapped(tap)) { delay(20); continue; }
if (!TouchInput::wasTapped(tap)) { MenuStars::update(tft); delay(20); continue; }
bool handled = false;
for (uint8_t i = 0; i < 12 && !handled; i++) {
@@ -131,6 +133,7 @@ void run(TFT_eSPI& tft) {
constexpr int16_t REMOVE_BTN_W = 60;
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -188,6 +191,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

View File

@@ -1,6 +1,7 @@
#include "logbook_files_screen.h"
#include "flight_logbook.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -74,6 +75,7 @@ void run(TFT_eSPI& tft) {
}
drawButton(tft, backBtn, I18n::t(StringId::BACK));
MenuStars::reset();
bool done = false;
while (!done) {
@@ -81,6 +83,7 @@ void run(TFT_eSPI& tft) {
if (TouchInput::wasTapped(tap) && backBtn.contains(tap.x, tap.y)) {
done = true;
}
MenuStars::update(tft);
delay(20);
}
}

View File

@@ -29,6 +29,7 @@
#include "screenshot.h"
#include "i18n.h"
#include "first_run_language_screen.h"
#include "menu_stars.h"
#include "ui_font.h"
TFT_eSPI tft = TFT_eSPI();
@@ -256,6 +257,7 @@ void setup() {
uint32_t waitStart = millis();
while (WifiMgr::getState() == WifiMgr::State::Connecting && millis() - waitStart < 16000) {
WifiMgr::update();
MenuStars::update(tft);
delay(100);
}
@@ -280,6 +282,7 @@ void setup() {
while (LocationManager::currentSource() == LocationManager::Source::None &&
millis() - locStart < 8000) {
LocationManager::requestIpLookupIfNeeded();
MenuStars::update(tft);
delay(200);
}
SplashScreen::setStatusLine(tft, 2, I18n::t(StringId::SPLASH_READY));
@@ -294,7 +297,7 @@ void setup() {
NetTask::begin();
SplashScreen::waitRemaining();
SplashScreen::waitRemaining(tft);
drawHeader();
updateStatusLine();

View File

@@ -10,6 +10,7 @@
#include "units_screen.h"
#include "settings_backup.h"
#include "settings_store.h"
#include "menu_stars.h"
#include "i18n.h"
#include "config.h"
@@ -77,6 +78,7 @@ namespace {
void run(TFT_eSPI& tft) {
Page page = Page::Main;
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
@@ -101,6 +103,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}
@@ -132,6 +135,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}
@@ -170,6 +174,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}
@@ -227,6 +232,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

52
src/menu_stars.cpp Normal file
View File

@@ -0,0 +1,52 @@
#include "menu_stars.h"
#include "config.h"
namespace MenuStars {
namespace {
constexpr uint8_t STAR_COUNT = 34;
struct Star {
int16_t x, y;
uint8_t phase;
uint8_t speed;
};
Star stars[STAR_COUNT];
bool initialized = false;
uint32_t lastUpdateMs = 0;
constexpr uint32_t UPDATE_INTERVAL_MS = 60;
void initStars() {
randomSeed((uint32_t)esp_random());
for (uint8_t i = 0; i < STAR_COUNT; i++) {
stars[i].x = (int16_t)random(4, Config::SCREEN_WIDTH - 4);
stars[i].y = (int16_t)random(4, Config::SCREEN_HEIGHT - 4);
stars[i].phase = (uint8_t)random(0, 256);
stars[i].speed = (uint8_t)(1 + random(0, 3));
}
initialized = true;
}
}
void reset() {
initialized = false;
}
void update(TFT_eSPI& tft) {
if (!initialized) initStars();
uint32_t now = millis();
if (now - lastUpdateMs < UPDATE_INTERVAL_MS) return;
lastUpdateMs = now;
for (uint8_t i = 0; i < STAR_COUNT; i++) {
stars[i].phase += stars[i].speed;
uint8_t bright = (stars[i].phase < 128)
? (uint8_t)(stars[i].phase * 2)
: (uint8_t)((255 - stars[i].phase) * 2);
uint16_t color = tft.color565(0, bright, 0);
tft.drawPixel(stars[i].x, stars[i].y, color);
}
}
}

17
src/menu_stars.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <TFT_eSPI.h>
// Gemeinsames Sterne-Twinkle-Modul fuer ALLE Menue-/Untermenue-Bildschirme
// (schwarzer Hintergrund) sowie den Splash-Screen - dieselbe Optik wie im
// Flugzeug-Detail-Panel des Radars.
namespace MenuStars {
// Verteilt die Sterne neu ueber den ganzen Bildschirm - einmal beim
// Betreten eines neuen Screens aufrufen (NICHT bei jedem Redraw
// innerhalb desselben Screens, sonst "springt" die Animation staendig).
void reset();
// In der Warte-/Idle-Schleife eines Screens aufrufen (bei jedem
// Schleifendurchlauf ist ok - die Funktion drosselt sich intern selbst
// auf ca. alle 60ms, um das Display nicht unnoetig oft anzusprechen).
void update(TFT_eSPI& tft);
}

View File

@@ -1,4 +1,5 @@
#include "splash_screen.h"
#include "menu_stars.h"
namespace SplashScreen {
@@ -10,7 +11,6 @@ namespace {
constexpr int16_t STATUS_START_Y = 260;
constexpr uint8_t MAX_STATUS_LINES = 3;
// Dezente konzentrische Ringe + Fadenkreuz als "Zielfernrohr"-Hintergrund
void drawRadarReticle(TFT_eSPI& tft, int16_t cx, int16_t cy) {
uint16_t dim = 0x0320;
tft.drawCircle(cx, cy, 80, dim);
@@ -20,14 +20,12 @@ namespace {
tft.drawFastVLine(cx, cy - 80, 160, dim);
}
// Echte kleine Jet-Silhouette für den Hintergrund
void drawMiniJet(TFT_eSPI& tft, int16_t x, int16_t y, uint16_t color) {
tft.drawLine(x, y - 10, x, y + 12, color);
tft.drawLine(x - 12, y + 2, x + 12, y + 2, color);
tft.drawLine(x - 5, y + 10, x + 5, y + 10, color);
}
// Echte kleine Helikopter-Silhouette für den Hintergrund
void drawMiniHeli(TFT_eSPI& tft, int16_t x, int16_t y, uint16_t color) {
tft.drawLine(x - 8, y - 6, x + 8, y - 6, color);
tft.drawLine(x, y - 6, x, y + 4, color);
@@ -35,41 +33,33 @@ namespace {
tft.drawLine(x - 4, y + 7, x + 4, y + 7, color);
}
// Haupt-Flugzeug in der Mitte (Unverändert)
void drawAirplane(TFT_eSPI& tft, int16_t cx) {
uint16_t color = TFT_GREEN;
// Rumpf (nur Umriss)
tft.drawTriangle(cx + 15, 142, cx - 15, 200, cx - 10, 202, color);
// Deltafluegel (nur Umriss)
tft.drawTriangle(cx + 5, 164, cx - 47, 175, cx - 3, 179, color);
tft.drawTriangle(cx + 5, 164, cx + 30, 211, cx - 3, 179, color);
// Leitwerk (nur Umriss)
tft.drawTriangle(cx - 11, 198, cx - 23, 201, cx - 6, 210, color);
}
}
void begin(TFT_eSPI& tft) {
startMs = millis();
MenuStars::reset();
int16_t cx = tft.width() / 2;
tft.fillScreen(TFT_BLACK);
drawRadarReticle(tft, cx, 174);
// Hintergrund-Flugzeuge & Helikopter dezent im Hintergrund - gleicher
// gedaempfter Gruenton wie die Radar-Ringe (0x0320), NICHT das volle
// TFT_GREEN (das war vorher gleich hell wie das zentrale Flugzeug und
// wirkte dadurch nicht wie ein dezenter Hintergrund).
uint16_t dimGreen = 0x0320;
drawMiniJet(tft, cx - 45, 135, dimGreen);
drawMiniJet(tft, cx + 50, 160, dimGreen);
drawMiniHeli(tft, cx - 35, 215, dimGreen);
drawMiniHeli(tft, cx + 45, 115, dimGreen);
// Zentrales Flugzeug (unverändert im Vordergrund)
drawAirplane(tft, cx);
tft.setTextDatum(MC_DATUM);
@@ -97,10 +87,12 @@ void setStatusLine(TFT_eSPI& tft, uint8_t slot, const String& text, uint16_t col
tft.setTextDatum(TL_DATUM);
}
void waitRemaining() {
void waitRemaining(TFT_eSPI& tft) {
uint32_t elapsed = millis() - startMs;
if (elapsed < MIN_DISPLAY_MS) {
delay(MIN_DISPLAY_MS - elapsed);
while (elapsed < MIN_DISPLAY_MS) {
MenuStars::update(tft);
delay(20);
elapsed = millis() - startMs;
}
}

View File

@@ -4,6 +4,11 @@
namespace SplashScreen {
void begin(TFT_eSPI& tft);
void setStatusLine(TFT_eSPI& tft, uint8_t slot, const String& text, uint16_t color = TFT_WHITE);
void waitRemaining();
// Blockiert, bis seit begin() mindestens MIN_DISPLAY_MS vergangen sind.
// Direkt vor dem Verlassen des Splash-Screens aufrufen. Zeichnet waehrend
// des Wartens dieselbe Sterne-Animation wie die Menues.
void waitRemaining(TFT_eSPI& tft);
}

View File

@@ -1,6 +1,7 @@
#include "stats_screen.h"
#include "flight_logbook.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -24,12 +25,6 @@ namespace {
tft.setTextDatum(TL_DATUM);
}
// Label (gedaempftes Gruen) direkt ueber dem Wert (helles Gruen) - BEIDE
// in derselben Schriftgroesse (Size 1). Bewusst KEINE gemischten
// Groessen mehr in einer Zeile: das Zusammenspiel aus Grundlinien-
// Verankerung + Size-2-Skalierung unseres Fonts fuehrte trotz
// rechnerisch korrektem Abstand zu sichtbaren Ueberschneidungen. Mit
// einheitlicher Groesse ist der noetige Abstand simpel und zuverlaessig.
void drawStatRow(TFT_eSPI& tft, int16_t labelY, const String& label, const String& value) {
tft.setTextColor(TFT_DARKGREEN, TFT_BLACK);
tft.setCursor(10, labelY);
@@ -108,6 +103,7 @@ void run(TFT_eSPI& tft) {
};
redraw();
MenuStars::reset();
bool done = false;
while (!done) {
@@ -136,6 +132,7 @@ void run(TFT_eSPI& tft) {
done = true;
}
}
MenuStars::update(tft);
delay(20);
}
}

View File

@@ -1,6 +1,7 @@
#include "units_screen.h"
#include "settings_store.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "i18n.h"
#include "config.h"
@@ -40,6 +41,7 @@ void run(TFT_eSPI& tft) {
StringId labels[MODE_COUNT] = {StringId::UNITS_AUTO, StringId::UNITS_METRIC, StringId::UNITS_IMPERIAL};
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -60,6 +62,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

View File

@@ -2,6 +2,7 @@
#include "wifi_manager.h"
#include "wifi_setup_screen.h"
#include "touch_input.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -32,6 +33,7 @@ void run(TFT_eSPI& tft) {
constexpr int16_t REMOVE_BTN_W = 60;
bool done = false;
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -77,6 +79,7 @@ void run(TFT_eSPI& tft) {
TouchInput::Point tap;
while (true) {
if (TouchInput::wasTapped(tap)) break;
MenuStars::update(tft);
delay(20);
}

View File

@@ -1,6 +1,7 @@
#include "wifi_setup_screen.h"
#include "touch_input.h"
#include "wifi_manager.h"
#include "menu_stars.h"
#include "config.h"
#include "i18n.h"
@@ -187,6 +188,7 @@ namespace {
}
bool run(TFT_eSPI& tft) {
MenuStars::reset();
stage = Stage::Scanning;
skipped = false;
connectSucceeded = false;
@@ -332,6 +334,7 @@ bool run(TFT_eSPI& tft) {
}
if (!needsRedraw) {
MenuStars::update(tft);
delay(20);
continue;
}