#pragma once #include #include "theme.h" // Icons drawn procedurally with M5Stack graphics primitives instead of // stored RGB565 bitmaps, to keep flash usage small. namespace Icons { 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++) { float angle = i * (PI / 4.0); int x1 = cx + cos(angle) * (r + 4); int y1 = cy + sin(angle) * (r + 4); int x2 = cx + cos(angle) * (r + 10); int y2 = cy + sin(angle) * (r + 10); M5.Lcd.drawLine(x1, y1, x2, y2, Theme::ACCENT_SUN); } } 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); } 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); } 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; M5.Lcd.drawLine(x, cy, x - 3, cy + 8, Theme::ACCENT_RAIN); } } // 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': if (isNight) drawMoon(cx, cy, r); else drawSun(cx, cy, r); break; case 'b': drawCloud(cx, cy, r * 2 / 3); break; case 'r': drawCloud(cx, cy - 5, r * 2 / 3); drawRainDrops(cx, cy + r / 2, 3); break; default: drawCloud(cx, cy, r * 2 / 3); break; } } 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); } 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); M5.Lcd.setCursor(x + w / 2 - 4, y + h / 2 - 4); M5.Lcd.print("U"); } 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); M5.Lcd.setCursor(x + w / 2 - 4, y + h / 2 - 4); M5.Lcd.print("S"); } // 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); 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); } 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); M5.Lcd.setCursor(cx - 3, cy - 8); M5.Lcd.print("!"); } } // namespace Icons