improve ui

This commit is contained in:
2026-08-02 08:06:35 +02:00
parent c6c576174b
commit 65e62f6a39
25 changed files with 298 additions and 740 deletions
+54 -32
View File
@@ -2,16 +2,10 @@
#include <M5Stack.h>
#include "theme.h"
// Design note: instead of storing large RGB565 bitmap arrays (which would
// bloat flash usage for a first version), icons are drawn procedurally with
// M5Stack's canvas primitives (circles, arcs, lines). This keeps the binary
// small while still giving a colorful, modern look. If you later want true
// pixel-art bitmaps, replace the bodies of these functions with
// M5.Lcd.drawBitmap(...) calls against RGB565 arrays generated from PNGs.
// Icons drawn procedurally with M5Stack graphics primitives instead of
// stored RGB565 bitmaps, to keep flash usage small.
namespace Icons {
// Draws a sun icon centered at (cx, cy) with given radius
inline void drawSun(int cx, int cy, int r) {
M5.Lcd.fillCircle(cx, cy, r, Theme::ACCENT_SUN);
for (int i = 0; i < 8; i++) {
@@ -24,21 +18,18 @@ inline void drawSun(int cx, int cy, int r) {
}
}
// Draws a moon icon (crescent) centered at (cx, cy)
inline void drawMoon(int cx, int cy, int r) {
M5.Lcd.fillCircle(cx, cy, r, Theme::TEXT_DIM);
M5.Lcd.fillCircle(cx + r / 2, cy - r / 3, r, Theme::BG);
}
// Draws a cloud icon centered at (cx, cy)
inline void drawCloud(int cx, int cy, int scale) {
M5.Lcd.fillCircle(cx - scale, cy, scale, Theme::TEXT_DIM);
M5.Lcd.fillCircle(cx + scale, cy, scale, Theme::TEXT_DIM);
M5.Lcd.fillCircle(cx, cy - scale / 2, scale + 2, Theme::TEXT_DIM);
M5.Lcd.fillRect(cx - scale, cy, scale * 2, scale, Theme::TEXT_DIM);
inline void drawCloud(int cx, int cy, int scale, uint16_t color = Theme::TEXT_DIM) {
M5.Lcd.fillCircle(cx - scale, cy, scale, color);
M5.Lcd.fillCircle(cx + scale, cy, scale, color);
M5.Lcd.fillCircle(cx, cy - scale / 2, scale + 2, color);
M5.Lcd.fillRect(cx - scale, cy, scale * 2, scale, color);
}
// Draws rain drops below a given y position
inline void drawRainDrops(int cx, int cy, int count = 3) {
for (int i = 0; i < count; i++) {
int x = cx - (count - 1) * 5 + i * 10;
@@ -46,23 +37,46 @@ inline void drawRainDrops(int cx, int cy, int count = 3) {
}
}
// Combined weather icon based on the API "symbol" field.
// symbol examples: "mo____" (clear/moon), "mb____" (cloudy/moon),
// "wb____" (cloudy/day). First char roughly encodes day(w)/night(m),
// second char encodes condition (o=clear, b=cloudy, r=rain, etc).
inline void drawWeatherIcon(const String &symbol, int cx, int cy, int r = 20) {
// Lightning bolt used for thunderstorm icon.
inline void drawLightningBolt(int cx, int cy, int size, uint16_t color = Theme::ACCENT_STORM) {
int x0 = cx + size / 4, y0 = cy - size;
int x1 = cx - size / 3, y1 = cy;
int x2 = cx, y2 = cy;
int x3 = cx - size / 6, y3 = cy + size;
M5.Lcd.drawLine(x0, y0, x1, y1, color);
M5.Lcd.drawLine(x1, y1, x2, y2, color);
M5.Lcd.drawLine(x2, y2, x3, y3, color);
M5.Lcd.drawLine(x0 + 1, y0, x1 + 1, y1, color);
M5.Lcd.drawLine(x1 + 1, y1, x2 + 1, y2, color);
}
// Thunderstorm: dark cloud + bolt, visually distinct from plain "bewoelkt".
inline void drawThunderstorm(int cx, int cy, int scale) {
drawCloud(cx, cy - scale / 3, scale, Theme::TEXT_DIM);
drawLightningBolt(cx, cy + scale / 2, scale, Theme::ACCENT_STORM);
}
// symbol: e.g. "mo____" (clear/night), "mb____" (cloudy/night), "wb____"
// (cloudy/day). description used as secondary signal to catch "Gewitter".
inline void drawWeatherIcon(const String &symbol, const String &description, int cx, int cy, int r = 20) {
bool isNight = symbol.length() > 0 && symbol.charAt(0) == 'm';
char condition = symbol.length() > 1 ? symbol.charAt(1) : 'o';
bool isThunder = (condition == 't') || (description.indexOf("Gewitter") >= 0);
if (isThunder) {
drawThunderstorm(cx, cy, r * 2 / 3);
return;
}
switch (condition) {
case 'o': // clear
case 'o':
if (isNight) drawMoon(cx, cy, r);
else drawSun(cx, cy, r);
break;
case 'b': // cloudy
case 'b':
drawCloud(cx, cy, r * 2 / 3);
break;
case 'r': // rain
case 'r':
drawCloud(cx, cy - 5, r * 2 / 3);
drawRainDrops(cx, cy + r / 2, 3);
break;
@@ -72,13 +86,15 @@ inline void drawWeatherIcon(const String &symbol, int cx, int cy, int r = 20) {
}
}
// Small rain-warning banner icon (drop with exclamation-ish accent)
inline void drawWeatherIcon(const String &symbol, int cx, int cy, int r = 20) {
drawWeatherIcon(symbol, String(""), cx, cy, r);
}
inline void drawRainWarning(int cx, int cy) {
M5.Lcd.fillTriangle(cx, cy - 8, cx - 6, cy + 6, cx + 6, cy + 6, Theme::ACCENT_RAIN);
M5.Lcd.fillCircle(cx, cy + 2, 2, Theme::BG);
}
// Simple "U" badge for U-Bahn
inline void drawUBahnBadge(int x, int y, int w, int h) {
M5.Lcd.fillRoundRect(x, y, w, h, 4, Theme::ACCENT_UBAHN);
M5.Lcd.setTextColor(Theme::TEXT, Theme::ACCENT_UBAHN);
@@ -86,7 +102,6 @@ inline void drawUBahnBadge(int x, int y, int w, int h) {
M5.Lcd.print("U");
}
// Simple "S" badge for S-Bahn
inline void drawSBahnBadge(int x, int y, int w, int h) {
M5.Lcd.fillRoundRect(x, y, w, h, 4, Theme::ACCENT_SBAHN);
M5.Lcd.setTextColor(Theme::TEXT, Theme::ACCENT_SBAHN);
@@ -94,17 +109,24 @@ inline void drawSBahnBadge(int x, int y, int w, int h) {
M5.Lcd.print("S");
}
// Calendar icon: simple rectangle with a top bar and a page-marker dot
// Proper calendar icon (rounded body, header bar, binder rings, day-dot),
// replacing the earlier checkbox-style placeholder.
inline void drawCalendarIcon(int cx, int cy, int size) {
int x = cx - size / 2;
int y = cy - size / 2;
M5.Lcd.fillRoundRect(x, y, size, size, 3, Theme::BG);
M5.Lcd.drawRoundRect(x, y, size, size, 3, Theme::ACCENT_CALENDAR);
M5.Lcd.fillRect(x, y, size, size / 4, Theme::ACCENT_CALENDAR);
M5.Lcd.fillCircle(cx, cy + size / 6, 2, Theme::TEXT);
int headerH = size / 3;
M5.Lcd.fillRect(x + 1, y + 1, size - 2, headerH, Theme::ACCENT_CALENDAR);
M5.Lcd.fillRect(x + size / 4 - 1, y - 2, 2, 4, Theme::ACCENT_CALENDAR);
M5.Lcd.fillRect(x + size * 3 / 4 - 1, y - 2, 2, 4, Theme::ACCENT_CALENDAR);
M5.Lcd.fillCircle(cx, y + headerH + (size - headerH) / 2, 2, Theme::TEXT);
}
// Retry / error icon: circular arrow suggestion using arcs (approximated
// with a broken circle) plus an exclamation mark for simplicity.
inline void drawRetryIcon(int cx, int cy, int r) {
M5.Lcd.drawCircle(cx, cy, r, Theme::ACCENT_ERROR);
M5.Lcd.setTextColor(Theme::ACCENT_ERROR, Theme::BG);