Compare commits
3 commits
4c5967d3c5
...
d614ea633a
| Author | SHA1 | Date | |
|---|---|---|---|
| d614ea633a | |||
| f6caf547fe | |||
| 63a7f8161a |
11 changed files with 2724 additions and 574 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
#include <pgmspace.h>
|
||||||
const uint8_t DSEG7_Modern_BoldItalic_44[] PROGMEM = {
|
const uint8_t DSEG7_Modern_BoldItalic_44[] PROGMEM = {
|
||||||
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2C,
|
0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2C,
|
||||||
|
|
|
||||||
490
sketch/obd2_gauge/cluster_screen.h
Normal file
490
sketch/obd2_gauge/cluster_screen.h
Normal file
|
|
@ -0,0 +1,490 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <TFT_eSPI.h>
|
||||||
|
#include "gps_module.h"
|
||||||
|
#include "DSEG7_Modern_BoldItalic_34.h"
|
||||||
|
#include "DSEG7_Modern_BoldItalic_44.h"
|
||||||
|
#include "rainbow_text.h"
|
||||||
|
|
||||||
|
extern TFT_eSPI tft;
|
||||||
|
extern uint16_t getThemePrimaryColor();
|
||||||
|
extern uint16_t getThemeAccentColor();
|
||||||
|
extern uint16_t getThemeBgColor();
|
||||||
|
extern bool isRainbowTheme();
|
||||||
|
extern bool isYapaTheme();
|
||||||
|
extern int8_t currentScreenPage;
|
||||||
|
extern int8_t fullScreenCell;
|
||||||
|
extern float currentRpm;
|
||||||
|
extern float last_valid_data[];
|
||||||
|
extern float tempEngineCoolant;
|
||||||
|
extern void drawPidIcon(int x, int y, const String &pidStr);
|
||||||
|
extern void drawPidIconToSprite(TFT_eSprite &s, int ix, int iy, const String &pidStr, int y_slice, int slice_h, int global_y);
|
||||||
|
extern void draw7SegDegreeC(TFT_eSPI &dst, int bx, int by, uint16_t color, uint16_t bgCol, bool rainbow);
|
||||||
|
|
||||||
|
// Data extractors
|
||||||
|
inline float getClusterRpmVal() {
|
||||||
|
if (currentRpm > 0.0f) return currentRpm;
|
||||||
|
if (last_valid_data[2] > 0.0f) return last_valid_data[2];
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getClusterSpeedVal() {
|
||||||
|
if (isGpsSpeedValid()) return gpsSpeedKmph;
|
||||||
|
if (last_valid_data[1] >= 0.0f) return last_valid_data[1];
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isClusterSpeedFromGps() {
|
||||||
|
return isGpsSpeedValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getClusterCoolantVal() {
|
||||||
|
if (last_valid_data[0] > -900.0f) return last_valid_data[0];
|
||||||
|
if (tempEngineCoolant > -900.0f) return tempEngineCoolant;
|
||||||
|
return -999.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getClusterVoltVal() {
|
||||||
|
if (last_valid_data[3] > 0.0f) return last_valid_data[3];
|
||||||
|
return -999.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching variables for zero-flicker live redraws
|
||||||
|
static int oldClusterRpm = -999;
|
||||||
|
static int oldClusterSpd = -999;
|
||||||
|
static int oldClusterCoolant = -999;
|
||||||
|
static float oldClusterVolt = -999.0f;
|
||||||
|
static bool oldClusterGpsLock = false;
|
||||||
|
static uint32_t lastClusterUpdate = 0;
|
||||||
|
|
||||||
|
inline void syncClusterTrackers() {
|
||||||
|
oldClusterRpm = (int)round(getClusterRpmVal());
|
||||||
|
oldClusterSpd = (int)round(getClusterSpeedVal());
|
||||||
|
float c = getClusterCoolantVal();
|
||||||
|
oldClusterCoolant = (c > -900.0f) ? (int)round(c) : -999;
|
||||||
|
oldClusterVolt = getClusterVoltVal();
|
||||||
|
oldClusterGpsLock = isClusterSpeedFromGps();
|
||||||
|
lastClusterUpdate = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: draw 5 top pagination dots (page 4 active)
|
||||||
|
inline void drawClusterDots(int x_offset = 0) {
|
||||||
|
uint16_t actCol = isRainbowTheme() ? getRainbowScreenColor(188, 2) : (isYapaTheme() ? getYapaColor(4) : getThemePrimaryColor());
|
||||||
|
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB);
|
||||||
|
tft.fillCircle(146 + x_offset, 2, 2, 0x5AEB);
|
||||||
|
tft.fillCircle(160 + x_offset, 2, 2, 0x5AEB);
|
||||||
|
tft.fillCircle(174 + x_offset, 2, 2, 0x5AEB);
|
||||||
|
tft.fillCircle(188 + x_offset, 2, 2, actCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw static framing of all 4 cards
|
||||||
|
inline void drawClusterBaseCards(int x_offset = 0) {
|
||||||
|
uint16_t cardBg = 0x10A2;
|
||||||
|
uint16_t border = 0x2945;
|
||||||
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
|
uint16_t accCol = getThemeAccentColor();
|
||||||
|
|
||||||
|
uint16_t cRpm = isRainbowTheme() ? getRainbowScreenColor(20, 20) : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
|
uint16_t cSpd = isRainbowTheme() ? getRainbowScreenColor(20, 70) : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
|
uint16_t cCool = isRainbowTheme() ? getRainbowScreenColor(20, 150) : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
|
uint16_t cVolt = isRainbowTheme() ? getRainbowScreenColor(180, 150) : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
|
|
||||||
|
// 1. TACHOMETER CARD (x: 8, y: 10, w: 304, h: 42)
|
||||||
|
tft.fillRoundRect(8 + x_offset, 10, 304, 42, 5, cardBg);
|
||||||
|
tft.drawRoundRect(8 + x_offset, 10, 304, 42, 5, border);
|
||||||
|
tft.fillRoundRect(12 + x_offset, 14, 3, 34, 1, cRpm);
|
||||||
|
drawPidIcon(18 + x_offset, 14, "010C");
|
||||||
|
tft.setTextColor(0x8410, cardBg);
|
||||||
|
tft.drawString("RPM", 38 + x_offset, 16, 2);
|
||||||
|
// Tachometer background track (x: 76 to 216, w: 140, h: 12)
|
||||||
|
tft.fillRoundRect(76 + x_offset, 16, 140, 12, 3, 0x0841);
|
||||||
|
// RPM ticks
|
||||||
|
tft.drawString("1 2 3 4 5 6 7", 86 + x_offset, 31, 1);
|
||||||
|
|
||||||
|
// 2. SPEEDOMETER CARD (x: 8, y: 56, w: 304, h: 76)
|
||||||
|
tft.fillRoundRect(8 + x_offset, 56, 304, 76, 5, cardBg);
|
||||||
|
tft.drawRoundRect(8 + x_offset, 56, 304, 76, 5, border);
|
||||||
|
tft.fillRoundRect(12 + x_offset, 60, 3, 68, 1, cSpd);
|
||||||
|
drawPidIcon(18 + x_offset, 60, "010D");
|
||||||
|
tft.setTextColor(0x8410, cardBg);
|
||||||
|
tft.drawString("VELOCIDAD", 38 + x_offset, 62, 2);
|
||||||
|
// Background speed glow rail
|
||||||
|
tft.fillRoundRect(18 + x_offset, 124, 284, 3, 1, 0x0841);
|
||||||
|
|
||||||
|
// 3. COOLANT TEMP CARD (x: 8, y: 136, w: 148, h: 98)
|
||||||
|
tft.fillRoundRect(8 + x_offset, 136, 148, 98, 5, cardBg);
|
||||||
|
tft.drawRoundRect(8 + x_offset, 136, 148, 98, 5, border);
|
||||||
|
tft.fillRoundRect(12 + x_offset, 140, 3, 90, 1, cCool);
|
||||||
|
drawPidIcon(18 + x_offset, 140, "0105");
|
||||||
|
tft.setTextColor(0x8410, cardBg);
|
||||||
|
tft.drawString("REFRIG.", 38 + x_offset, 142, 2);
|
||||||
|
// Thermal bar rail (x: 18, y: 196, w: 128, h: 8)
|
||||||
|
tft.fillRoundRect(18 + x_offset, 196, 128, 8, 3, 0x0841);
|
||||||
|
tft.drawString("40`C", 18 + x_offset, 210, 1);
|
||||||
|
tft.drawString("120`C", 112 + x_offset, 210, 1);
|
||||||
|
|
||||||
|
// 4. BATTERY VOLTAGE CARD (x: 164, y: 136, w: 148, h: 98)
|
||||||
|
tft.fillRoundRect(164 + x_offset, 136, 148, 98, 5, cardBg);
|
||||||
|
tft.drawRoundRect(164 + x_offset, 136, 148, 98, 5, border);
|
||||||
|
tft.fillRoundRect(168 + x_offset, 140, 3, 90, 1, cVolt);
|
||||||
|
drawPidIcon(174 + x_offset, 140, "ATRV");
|
||||||
|
tft.setTextColor(0x8410, cardBg);
|
||||||
|
tft.drawString("BATERIA", 194 + x_offset, 142, 2);
|
||||||
|
// Voltage bar rail (x: 174, y: 196, w: 128, h: 8)
|
||||||
|
tft.fillRoundRect(174 + x_offset, 196, 128, 8, 3, 0x0841);
|
||||||
|
tft.drawString("10V", 174 + x_offset, 210, 1);
|
||||||
|
tft.drawString("16V", 272 + x_offset, 210, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial direct draw of Page 4
|
||||||
|
inline void drawClusterScreen(int x_offset = 0) {
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
drawClusterDots(x_offset);
|
||||||
|
drawClusterBaseCards(x_offset);
|
||||||
|
|
||||||
|
// Force full initial value render
|
||||||
|
oldClusterRpm = -999;
|
||||||
|
oldClusterSpd = -999;
|
||||||
|
oldClusterCoolant = -999;
|
||||||
|
oldClusterVolt = -999.0f;
|
||||||
|
oldClusterGpsLock = false;
|
||||||
|
|
||||||
|
void updateClusterScreen(bool forceRedraw = false);
|
||||||
|
updateClusterScreen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Live zero-flicker non-blocking update of Page 4
|
||||||
|
inline void updateClusterScreen(bool forceRedraw) {
|
||||||
|
if (currentScreenPage != 4 || fullScreenCell != -1) return;
|
||||||
|
|
||||||
|
uint16_t cardBg = 0x10A2;
|
||||||
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
|
uint16_t accCol = getThemeAccentColor();
|
||||||
|
|
||||||
|
uint16_t cRpm = isRainbowTheme() ? getRainbowScreenColor(20, 20) : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
|
uint16_t cSpd = isRainbowTheme() ? getRainbowScreenColor(20, 70) : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
|
uint16_t cCool = isRainbowTheme() ? getRainbowScreenColor(20, 150) : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
|
uint16_t cVolt = isRainbowTheme() ? getRainbowScreenColor(180, 150) : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// 1. TACHOMETER (RPM)
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
float curRpmF = getClusterRpmVal();
|
||||||
|
int curRpm = (int)round(curRpmF);
|
||||||
|
if (forceRedraw || abs(curRpm - oldClusterRpm) >= 20 || (curRpm == 0 && oldClusterRpm != 0)) {
|
||||||
|
oldClusterRpm = curRpm;
|
||||||
|
|
||||||
|
// Erase numeric text area
|
||||||
|
tft.fillRect(222, 14, 84, 26, cardBg);
|
||||||
|
tft.setTextPadding(0);
|
||||||
|
if (curRpm > 0) {
|
||||||
|
uint16_t rpmCol = (curRpm >= 6000) ? TFT_RED : ((curRpm >= 4500) ? 0xFD60 : cRpm);
|
||||||
|
tft.setTextColor(rpmCol, cardBg);
|
||||||
|
String rpmStr = String(curRpm);
|
||||||
|
tft.drawRightString(rpmStr, 302, 16, 4);
|
||||||
|
} else {
|
||||||
|
tft.setTextColor(0x632C, cardBg);
|
||||||
|
tft.drawRightString("---", 302, 16, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segmented Tachometer Bar (12 segments between x: 78 and 214)
|
||||||
|
// 0 to 7000 RPM -> ~583 RPM per segment
|
||||||
|
int activeSegs = map(constrain(curRpm, 0, 7000), 0, 7000, 0, 12);
|
||||||
|
for (int s = 0; s < 12; s++) {
|
||||||
|
int sx = 78 + s * 11;
|
||||||
|
uint16_t segCol;
|
||||||
|
if (s < activeSegs) {
|
||||||
|
if (s >= 10) segCol = TFT_RED;
|
||||||
|
else if (s >= 8) segCol = 0xFD60;
|
||||||
|
else segCol = isRainbowTheme() ? getRainbowScreenColor(sx, 20) : cRpm;
|
||||||
|
} else {
|
||||||
|
segCol = 0x0841; // inactive dark track
|
||||||
|
}
|
||||||
|
tft.fillRect(sx, 18, 9, 8, segCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// 2. SPEEDOMETER (VELOCIDAD)
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
float curSpdF = getClusterSpeedVal();
|
||||||
|
int curSpd = (int)round(curSpdF);
|
||||||
|
bool isGps = isClusterSpeedFromGps();
|
||||||
|
|
||||||
|
if (forceRedraw || curSpd != oldClusterSpd || isGps != oldClusterGpsLock) {
|
||||||
|
oldClusterSpd = curSpd;
|
||||||
|
oldClusterGpsLock = isGps;
|
||||||
|
|
||||||
|
// Source Pill (GPS / OBD)
|
||||||
|
tft.fillRect(116, 61, 46, 14, cardBg);
|
||||||
|
if (isGps) {
|
||||||
|
tft.fillRoundRect(116, 61, 42, 14, 3, 0x0254);
|
||||||
|
tft.setTextColor(0x07FF, 0x0254);
|
||||||
|
tft.drawString("GPS", 125, 63, 1);
|
||||||
|
} else {
|
||||||
|
tft.fillRoundRect(116, 61, 42, 14, 3, 0x18C3);
|
||||||
|
tft.setTextColor(0x8410, 0x18C3);
|
||||||
|
tft.drawString("OBD", 125, 63, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Giant Speed Display
|
||||||
|
tft.fillRect(166, 60, 138, 56, cardBg);
|
||||||
|
String spdStr = String(curSpd);
|
||||||
|
|
||||||
|
tft.loadFont(DSEG7_Modern_BoldItalic_44);
|
||||||
|
uint16_t spdCol = isRainbowTheme() ? getRainbowScreenColor(210, 80) : cSpd;
|
||||||
|
tft.setTextColor(spdCol, cardBg);
|
||||||
|
tft.drawRightString(spdStr, 248, 64, 1);
|
||||||
|
tft.unloadFont();
|
||||||
|
|
||||||
|
// Unit "km/h"
|
||||||
|
tft.setTextColor(0xBDD7, cardBg);
|
||||||
|
tft.drawString("km/h", 254, 88, 2);
|
||||||
|
|
||||||
|
// Dynamic Bottom Speed Rail (w = 284)
|
||||||
|
int fillSpdW = map(constrain(curSpd, 0, 200), 0, 200, 0, 284);
|
||||||
|
tft.fillRect(18, 124, 284, 3, 0x0841);
|
||||||
|
if (fillSpdW > 0) {
|
||||||
|
if (isRainbowTheme()) {
|
||||||
|
for (int bx = 0; bx < fillSpdW; bx++) {
|
||||||
|
tft.drawFastVLine(18 + bx, 124, 3, getRainbowScreenColor(18 + bx, 124));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tft.fillRect(18, 124, fillSpdW, 3, cSpd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// 3. COOLANT TEMP (REFRIGERANTE)
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
float curCoolF = getClusterCoolantVal();
|
||||||
|
int curCool = (curCoolF > -900.0f) ? (int)round(curCoolF) : -999;
|
||||||
|
if (forceRedraw || curCool != oldClusterCoolant) {
|
||||||
|
oldClusterCoolant = curCool;
|
||||||
|
|
||||||
|
tft.fillRect(20, 158, 130, 36, cardBg);
|
||||||
|
if (curCool > -900) {
|
||||||
|
uint16_t coolCol = (curCool >= 105) ? TFT_RED : ((curCool < 70) ? 0x05BF : cCool);
|
||||||
|
tft.setTextColor(coolCol, cardBg);
|
||||||
|
String valStr = String(curCool);
|
||||||
|
tft.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
|
tft.drawRightString(valStr, 102, 160, 1);
|
||||||
|
tft.unloadFont();
|
||||||
|
|
||||||
|
draw7SegDegreeC(tft, 106, 164, coolCol, cardBg, isRainbowTheme());
|
||||||
|
|
||||||
|
// Progress bar (40 to 120 °C)
|
||||||
|
int barW = map(constrain(curCool, 40, 120), 40, 120, 0, 128);
|
||||||
|
tft.fillRect(18, 196, 128, 8, 0x0841);
|
||||||
|
if (barW > 0) {
|
||||||
|
tft.fillRoundRect(18, 196, barW, 8, 2, coolCol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tft.setTextColor(0x632C, cardBg);
|
||||||
|
tft.drawString("---", 60, 164, 4);
|
||||||
|
tft.fillRect(18, 196, 128, 8, 0x0841);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// 4. BATTERY VOLTAGE (BATERÍA)
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
float curVolt = getClusterVoltVal();
|
||||||
|
if (forceRedraw || abs(curVolt - oldClusterVolt) >= 0.08f) {
|
||||||
|
oldClusterVolt = curVolt;
|
||||||
|
|
||||||
|
tft.fillRect(174, 158, 130, 36, cardBg);
|
||||||
|
if (curVolt > 0.0f) {
|
||||||
|
uint16_t voltCol = (curVolt < 11.8f || curVolt > 15.0f) ? TFT_RED : ((curVolt >= 13.5f) ? 0x07E0 : cVolt);
|
||||||
|
String voltStr = String(curVolt, 1);
|
||||||
|
|
||||||
|
tft.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
|
tft.setTextColor(voltCol, cardBg);
|
||||||
|
tft.drawRightString(voltStr, 268, 160, 1);
|
||||||
|
tft.unloadFont();
|
||||||
|
|
||||||
|
tft.setTextColor(0xBDD7, cardBg);
|
||||||
|
tft.drawString("V", 274, 172, 2);
|
||||||
|
|
||||||
|
// Voltage bar (10.0 to 16.0 V)
|
||||||
|
int vBarW = map(constrain((int)(curVolt * 10), 100, 160), 100, 160, 0, 128);
|
||||||
|
tft.fillRect(174, 196, 128, 8, 0x0841);
|
||||||
|
if (vBarW > 0) {
|
||||||
|
tft.fillRoundRect(174, 196, vBarW, 8, 2, voltCol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tft.setTextColor(0x632C, cardBg);
|
||||||
|
tft.drawString("---", 216, 164, 4);
|
||||||
|
tft.fillRect(174, 196, 128, 8, 0x0841);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render Page 4 slice-by-slice into sprite (for double-buffered transitions)
|
||||||
|
inline void renderPage4ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int slice_h) {
|
||||||
|
uint16_t cardBg = 0x10A2;
|
||||||
|
uint16_t border = 0x2945;
|
||||||
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
|
uint16_t accCol = getThemeAccentColor();
|
||||||
|
|
||||||
|
uint16_t cRpm = isRainbowTheme() ? getRainbowScreenColor(20, 20) : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
|
uint16_t cSpd = isRainbowTheme() ? getRainbowScreenColor(20, 70) : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
|
uint16_t cCool = isRainbowTheme() ? getRainbowScreenColor(20, 150) : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
|
uint16_t cVolt = isRainbowTheme() ? getRainbowScreenColor(180, 150) : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
|
|
||||||
|
// Pagination dots on top slice (page 4 active)
|
||||||
|
if (y_slice == 0) {
|
||||||
|
uint16_t actCol = isRainbowTheme() ? getRainbowScreenColor(188, 2) : (isYapaTheme() ? getYapaColor(4) : priCol);
|
||||||
|
s.fillCircle(132, 2, 2, 0x5AEB);
|
||||||
|
s.fillCircle(146, 2, 2, 0x5AEB);
|
||||||
|
s.fillCircle(160, 2, 2, 0x5AEB);
|
||||||
|
s.fillCircle(174, 2, 2, 0x5AEB);
|
||||||
|
s.fillCircle(188, 2, 2, actCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. TACHOMETER CARD (y: 10 to 52)
|
||||||
|
int c0Y = 10 - y_slice;
|
||||||
|
if (c0Y < slice_h && c0Y + 42 > 0) {
|
||||||
|
s.fillRoundRect(8, c0Y, 304, 42, 5, cardBg);
|
||||||
|
s.drawRoundRect(8, c0Y, 304, 42, 5, border);
|
||||||
|
s.fillRoundRect(12, c0Y + 4, 3, 34, 1, cRpm);
|
||||||
|
drawPidIconToSprite(s, 18, c0Y + 4, "010C", y_slice, slice_h, 10);
|
||||||
|
s.setTextColor(0x8410, cardBg);
|
||||||
|
s.drawString("RPM", 38, c0Y + 6, 2);
|
||||||
|
|
||||||
|
// Tachometer background rail
|
||||||
|
s.fillRoundRect(76, c0Y + 6, 140, 12, 3, 0x0841);
|
||||||
|
s.drawString("1 2 3 4 5 6 7", 86, c0Y + 21, 1);
|
||||||
|
|
||||||
|
float curRpmF = getClusterRpmVal();
|
||||||
|
int curRpm = (int)round(curRpmF);
|
||||||
|
if (curRpm > 0) {
|
||||||
|
uint16_t rpmCol = (curRpm >= 6000) ? TFT_RED : ((curRpm >= 4500) ? 0xFD60 : cRpm);
|
||||||
|
s.setTextColor(rpmCol, cardBg);
|
||||||
|
s.drawRightString(String(curRpm), 302, c0Y + 6, 4);
|
||||||
|
|
||||||
|
int activeSegs = map(constrain(curRpm, 0, 7000), 0, 7000, 0, 12);
|
||||||
|
for (int seg = 0; seg < 12; seg++) {
|
||||||
|
int sx = 78 + seg * 11;
|
||||||
|
uint16_t segCol = 0x0841;
|
||||||
|
if (seg < activeSegs) {
|
||||||
|
if (seg >= 10) segCol = TFT_RED;
|
||||||
|
else if (seg >= 8) segCol = 0xFD60;
|
||||||
|
else segCol = isRainbowTheme() ? getRainbowScreenColor(sx, 20) : cRpm;
|
||||||
|
}
|
||||||
|
s.fillRect(sx, c0Y + 8, 9, 8, segCol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.setTextColor(0x632C, cardBg);
|
||||||
|
s.drawRightString("---", 302, c0Y + 6, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. SPEEDOMETER CARD (y: 56 to 132)
|
||||||
|
int c1Y = 56 - y_slice;
|
||||||
|
if (c1Y < slice_h && c1Y + 76 > 0) {
|
||||||
|
s.fillRoundRect(8, c1Y, 304, 76, 5, cardBg);
|
||||||
|
s.drawRoundRect(8, c1Y, 304, 76, 5, border);
|
||||||
|
s.fillRoundRect(12, c1Y + 4, 3, 68, 1, cSpd);
|
||||||
|
drawPidIconToSprite(s, 18, c1Y + 4, "010D", y_slice, slice_h, 56);
|
||||||
|
s.setTextColor(0x8410, cardBg);
|
||||||
|
s.drawString("VELOCIDAD", 38, c1Y + 6, 2);
|
||||||
|
|
||||||
|
bool isGps = isClusterSpeedFromGps();
|
||||||
|
if (isGps) {
|
||||||
|
s.fillRoundRect(116, c1Y + 5, 42, 14, 3, 0x0254);
|
||||||
|
s.setTextColor(0x07FF, 0x0254);
|
||||||
|
s.drawString("GPS", 125, c1Y + 7, 1);
|
||||||
|
} else {
|
||||||
|
s.fillRoundRect(116, c1Y + 5, 42, 14, 3, 0x18C3);
|
||||||
|
s.setTextColor(0x8410, 0x18C3);
|
||||||
|
s.drawString("OBD", 125, c1Y + 7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int curSpd = (int)round(getClusterSpeedVal());
|
||||||
|
String spdStr = String(curSpd);
|
||||||
|
s.loadFont(DSEG7_Modern_BoldItalic_44);
|
||||||
|
uint16_t spdCol = isRainbowTheme() ? getRainbowScreenColor(210, 80) : cSpd;
|
||||||
|
s.setTextColor(spdCol, cardBg);
|
||||||
|
s.drawRightString(spdStr, 248, c1Y + 8, 1);
|
||||||
|
s.unloadFont();
|
||||||
|
|
||||||
|
s.setTextColor(0xBDD7, cardBg);
|
||||||
|
s.drawString("km/h", 254, c1Y + 32, 2);
|
||||||
|
|
||||||
|
int fillSpdW = map(constrain(curSpd, 0, 200), 0, 200, 0, 284);
|
||||||
|
s.fillRect(18, c1Y + 68, 284, 3, 0x0841);
|
||||||
|
if (fillSpdW > 0) {
|
||||||
|
s.fillRect(18, c1Y + 68, fillSpdW, 3, cSpd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. COOLANT TEMP CARD (y: 136 to 234)
|
||||||
|
int c2Y = 136 - y_slice;
|
||||||
|
if (c2Y < slice_h && c2Y + 98 > 0) {
|
||||||
|
s.fillRoundRect(8, c2Y, 148, 98, 5, cardBg);
|
||||||
|
s.drawRoundRect(8, c2Y, 148, 98, 5, border);
|
||||||
|
s.fillRoundRect(12, c2Y + 4, 3, 90, 1, cCool);
|
||||||
|
drawPidIconToSprite(s, 18, c2Y + 4, "0105", y_slice, slice_h, 136);
|
||||||
|
s.setTextColor(0x8410, cardBg);
|
||||||
|
s.drawString("REFRIG.", 38, c2Y + 6, 2);
|
||||||
|
|
||||||
|
s.fillRect(18, c2Y + 60, 128, 8, 0x0841);
|
||||||
|
s.drawString("40`C", 18, c2Y + 74, 1);
|
||||||
|
s.drawString("120`C", 112, c2Y + 74, 1);
|
||||||
|
|
||||||
|
float curCoolF = getClusterCoolantVal();
|
||||||
|
int curCool = (curCoolF > -900.0f) ? (int)round(curCoolF) : -999;
|
||||||
|
if (curCool > -900) {
|
||||||
|
uint16_t coolCol = (curCool >= 105) ? TFT_RED : ((curCool < 70) ? 0x05BF : cCool);
|
||||||
|
s.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
|
s.setTextColor(coolCol, cardBg);
|
||||||
|
s.drawRightString(String(curCool), 102, c2Y + 24, 1);
|
||||||
|
s.unloadFont();
|
||||||
|
|
||||||
|
int barW = map(constrain(curCool, 40, 120), 40, 120, 0, 128);
|
||||||
|
if (barW > 0) {
|
||||||
|
s.fillRoundRect(18, c2Y + 60, barW, 8, 2, coolCol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.setTextColor(0x632C, cardBg);
|
||||||
|
s.drawString("---", 60, c2Y + 28, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. BATTERY VOLTAGE CARD (y: 136 to 234)
|
||||||
|
int c3Y = 136 - y_slice;
|
||||||
|
if (c3Y < slice_h && c3Y + 98 > 0) {
|
||||||
|
s.fillRoundRect(164, c3Y, 148, 98, 5, cardBg);
|
||||||
|
s.drawRoundRect(164, c3Y, 148, 98, 5, border);
|
||||||
|
s.fillRoundRect(168, c3Y + 4, 3, 90, 1, cVolt);
|
||||||
|
drawPidIconToSprite(s, 174, c3Y + 4, "ATRV", y_slice, slice_h, 136);
|
||||||
|
s.setTextColor(0x8410, cardBg);
|
||||||
|
s.drawString("BATERIA", 194, c3Y + 6, 2);
|
||||||
|
|
||||||
|
s.fillRect(174, c3Y + 60, 128, 8, 0x0841);
|
||||||
|
s.drawString("10V", 174, c3Y + 74, 1);
|
||||||
|
s.drawString("16V", 272, c3Y + 74, 1);
|
||||||
|
|
||||||
|
float curVolt = getClusterVoltVal();
|
||||||
|
if (curVolt > 0.0f) {
|
||||||
|
uint16_t voltCol = (curVolt < 11.8f || curVolt > 15.0f) ? TFT_RED : ((curVolt >= 13.5f) ? 0x07E0 : cVolt);
|
||||||
|
s.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
|
s.setTextColor(voltCol, cardBg);
|
||||||
|
s.drawRightString(String(curVolt, 1), 268, c3Y + 24, 1);
|
||||||
|
s.unloadFont();
|
||||||
|
s.setTextColor(0xBDD7, cardBg);
|
||||||
|
s.drawString("V", 274, c3Y + 36, 2);
|
||||||
|
|
||||||
|
int vBarW = map(constrain((int)(curVolt * 10), 100, 160), 100, 160, 0, 128);
|
||||||
|
if (vBarW > 0) {
|
||||||
|
s.fillRoundRect(174, c3Y + 60, vBarW, 8, 2, voltCol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.setTextColor(0x632C, cardBg);
|
||||||
|
s.drawString("---", 216, c3Y + 28, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
650
sketch/obd2_gauge/coords_font.h
Normal file
650
sketch/obd2_gauge/coords_font.h
Normal file
|
|
@ -0,0 +1,650 @@
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <TFT_eSPI.h>
|
||||||
|
#include "rainbow_text.h"
|
||||||
|
|
||||||
|
// High-definition 8-bit anti-aliased font data for GPS Navigation & Telemetry
|
||||||
|
// Generates zero heap fragmentation and provides smooth subpixel alpha blending
|
||||||
|
|
||||||
|
struct CoordsGlyphAA {
|
||||||
|
uint8_t w;
|
||||||
|
uint8_t h;
|
||||||
|
int8_t xOff;
|
||||||
|
int8_t yOff;
|
||||||
|
uint8_t xAdv;
|
||||||
|
uint16_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Title Font (13.5pt Bold AA: ALTITUD, RUMBO / BRUJULA, SATELITES GPS, COORDENADAS) - 2583 bytes
|
||||||
|
static const uint8_t s_navTitleAlpha[2583] PROGMEM = {
|
||||||
|
0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xFD, 0xF5,
|
||||||
|
0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xF7, 0xCA, 0xAF, 0xFE, 0x1D, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x60, 0xFF, 0x7A, 0x60, 0xFF, 0x75, 0x00, 0x00, 0x00, 0x00, 0xBA, 0xFF, 0x27, 0x11, 0xFB, 0xCE,
|
||||||
|
0x00, 0x00, 0x00, 0x17, 0xFC, 0xD5, 0x00, 0x00, 0xBA, 0xFF, 0x28, 0x00, 0x00, 0x6E, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0x82, 0x00, 0x00, 0xC8, 0xFF, 0x94, 0x84, 0x84, 0x88, 0xFE, 0xDB, 0x00,
|
||||||
|
0x22, 0xFF, 0xDF, 0x00, 0x00, 0x00, 0x00, 0xC5, 0xFF, 0x35, 0x7B, 0xFF, 0x88, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x6C, 0xFF, 0x8F, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xE1, 0x96, 0x11, 0x00, 0x10, 0xFF,
|
||||||
|
0xFA, 0x80, 0x80, 0x87, 0xD7, 0xFF, 0xA9, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x2D, 0xFF,
|
||||||
|
0xE0, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x06, 0x72, 0xFF, 0xAA, 0x00, 0x10, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xBC, 0x10, 0x00, 0x10, 0xFF, 0xF9, 0x7C, 0x7C, 0x7F, 0xAA, 0xFE, 0xC4, 0x08,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xFF, 0x5B, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xAC, 0xFF, 0x63, 0x10, 0xFF, 0xFA, 0x80, 0x80, 0x82, 0xA9, 0xFE, 0xF0, 0x1E, 0x10, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0xB4, 0x34, 0x00, 0x00, 0x00, 0x41, 0xB7, 0xEE, 0xF8, 0xDF, 0x96,
|
||||||
|
0x1B, 0x00, 0x00, 0x5B, 0xFD, 0xFF, 0xC3, 0xA1, 0xD0, 0xFF, 0xE4, 0x17, 0x09, 0xEC, 0xFF, 0x5F,
|
||||||
|
0x00, 0x00, 0x00, 0x84, 0xD4, 0x4C, 0x44, 0xFF, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x64, 0xFF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xFF, 0xAC, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xD9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xE4,
|
||||||
|
0xFF, 0x68, 0x00, 0x00, 0x00, 0x6B, 0xD3, 0x56, 0x00, 0x49, 0xFA, 0xFF, 0xC6, 0xA0, 0xC5, 0xFF,
|
||||||
|
0xEF, 0x29, 0x00, 0x00, 0x35, 0xAF, 0xEB, 0xFA, 0xE2, 0x9D, 0x21, 0x00, 0x10, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFC, 0xE8, 0xAD, 0x39, 0x00, 0x00, 0x10, 0xFF, 0xFA, 0x90, 0x97, 0xC3, 0xFF, 0xFC, 0x5C, 0x00,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x59, 0xFF, 0xF2, 0x11, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xC0, 0xFF, 0x59, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xFF, 0x7B, 0x10, 0xFF,
|
||||||
|
0xF4, 0x00, 0x00, 0x00, 0x00, 0x94, 0xFF, 0x74, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xC7,
|
||||||
|
0xFF, 0x4D, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x5C, 0xFF, 0xE9, 0x07, 0x10, 0xFF, 0xFA, 0x90,
|
||||||
|
0x92, 0xBC, 0xFF, 0xFA, 0x4D, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB2, 0x37, 0x00, 0x00,
|
||||||
|
0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x84, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x90, 0x90,
|
||||||
|
0x90, 0x4A, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0x10, 0xFF, 0xFA,
|
||||||
|
0x90, 0x90, 0x90, 0x90, 0x90, 0x0D, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
|
||||||
|
0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||||||
|
0x72, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0x0C, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x90, 0x90, 0x90, 0x06, 0x10, 0xFF, 0xF4, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x90, 0x90, 0x7E, 0x00,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xAF, 0xE9, 0xFA, 0xE6, 0xAB, 0x35, 0x00, 0x00, 0x00,
|
||||||
|
0x52, 0xFB, 0xFF, 0xC9, 0xA1, 0xC4, 0xFF, 0xF8, 0x3E, 0x00, 0x08, 0xE9, 0xFF, 0x6B, 0x00, 0x00,
|
||||||
|
0x00, 0x69, 0xD7, 0x68, 0x00, 0x43, 0xFF, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x64, 0xFF, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xFF, 0xAD, 0x00, 0x00,
|
||||||
|
0x2C, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x3F, 0xFF, 0xDC, 0x02, 0x00, 0x15, 0x7C, 0x7C, 0xE9, 0xFF,
|
||||||
|
0x04, 0x06, 0xE5, 0xFF, 0x72, 0x00, 0x00, 0x00, 0x09, 0xDF, 0xFF, 0x04, 0x00, 0x4C, 0xFA, 0xFF,
|
||||||
|
0xC9, 0x9E, 0xB5, 0xED, 0xFF, 0xC4, 0x01, 0x00, 0x00, 0x36, 0xAF, 0xEB, 0xFB, 0xE9, 0xB6, 0x5A,
|
||||||
|
0x03, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x2C, 0x10, 0xFF, 0xFC, 0xAC, 0xAC, 0xAC, 0xAC, 0xF2, 0xFF, 0x2C, 0x10, 0xFF,
|
||||||
|
0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8,
|
||||||
|
0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xD8, 0xFF, 0x2C, 0x10, 0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10,
|
||||||
|
0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10, 0xFF, 0xF4, 0x10, 0xFF,
|
||||||
|
0xF4, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xD4, 0x00, 0x00, 0x0D, 0x94, 0xA8,
|
||||||
|
0xFF, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xD4,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xD4, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x30, 0xFF, 0xD2, 0x83, 0xE4, 0x60, 0x00, 0x4F, 0xFF, 0xB5, 0x56, 0xFF, 0xF0, 0x9F,
|
||||||
|
0xE5, 0xFF, 0x5D, 0x00, 0x70, 0xDB, 0xF7, 0xDB, 0x6F, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00,
|
||||||
|
0x3A, 0xF4, 0xF1, 0x35, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x33, 0xF0, 0xF4, 0x3B, 0x00, 0x10, 0xFF,
|
||||||
|
0xF4, 0x00, 0x2C, 0xEC, 0xF6, 0x40, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x26, 0xE8, 0xF8, 0x46, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0xFF, 0xF9, 0xE3, 0xFF, 0xC6, 0x02, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xDB,
|
||||||
|
0xCA, 0xFF, 0x82, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF8, 0x10, 0x1C, 0xEC, 0xFE, 0x49, 0x00, 0x00,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x49, 0xFE, 0xED, 0x1F, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00,
|
||||||
|
0x86, 0xFF, 0xCB, 0x07, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x03, 0xC1, 0xFF, 0x99, 0x10, 0xFF,
|
||||||
|
0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x90, 0x90, 0x90, 0x12, 0x10,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x10, 0xFF, 0xFF, 0xCA, 0x00, 0x00, 0x00, 0x1B,
|
||||||
|
0xFF, 0xFF, 0xB8, 0x10, 0xFF, 0xFE, 0xFE, 0x1A, 0x00, 0x00, 0x68, 0xFE, 0xFF, 0xB8, 0x10, 0xFF,
|
||||||
|
0xD5, 0xFF, 0x68, 0x00, 0x00, 0xB5, 0xD6, 0xFF, 0xB8, 0x10, 0xFF, 0xB8, 0xDE, 0xB6, 0x00, 0x0A,
|
||||||
|
0xF7, 0x9A, 0xFF, 0xB8, 0x10, 0xFF, 0xBC, 0x95, 0xF8, 0x0C, 0x4F, 0xFF, 0x51, 0xFF, 0xB8, 0x10,
|
||||||
|
0xFF, 0xBC, 0x46, 0xFF, 0x54, 0x9C, 0xED, 0x14, 0xFF, 0xB8, 0x10, 0xFF, 0xBC, 0x05, 0xF0, 0x9B,
|
||||||
|
0xE4, 0xA2, 0x10, 0xFF, 0xB8, 0x10, 0xFF, 0xBC, 0x00, 0xA7, 0xF1, 0xFF, 0x52, 0x10, 0xFF, 0xB8,
|
||||||
|
0x10, 0xFF, 0xBC, 0x00, 0x58, 0xFF, 0xF7, 0x0B, 0x10, 0xFF, 0xB8, 0x10, 0xFF, 0xBC, 0x00, 0x0E,
|
||||||
|
0xF9, 0xB3, 0x00, 0x10, 0xFF, 0xB8, 0x10, 0xFF, 0xFF, 0x81, 0x00, 0x00, 0x00, 0xA0, 0xFF, 0x2C,
|
||||||
|
0x10, 0xFF, 0xFF, 0xF4, 0x19, 0x00, 0x00, 0xA0, 0xFF, 0x2C, 0x10, 0xFF, 0xE3, 0xFF, 0x9B, 0x00,
|
||||||
|
0x00, 0xA0, 0xFF, 0x2C, 0x10, 0xFF, 0xB5, 0xBC, 0xFC, 0x2B, 0x00, 0xA0, 0xFF, 0x2C, 0x10, 0xFF,
|
||||||
|
0xBB, 0x32, 0xFE, 0xB4, 0x00, 0xA0, 0xFF, 0x2C, 0x10, 0xFF, 0xBC, 0x00, 0xA6, 0xFF, 0x41, 0x9F,
|
||||||
|
0xFF, 0x2C, 0x10, 0xFF, 0xBC, 0x00, 0x21, 0xF9, 0xCC, 0x96, 0xFF, 0x2C, 0x10, 0xFF, 0xBC, 0x00,
|
||||||
|
0x00, 0x90, 0xFF, 0xDB, 0xFF, 0x2C, 0x10, 0xFF, 0xBC, 0x00, 0x00, 0x14, 0xF1, 0xFF, 0xFF, 0x2C,
|
||||||
|
0x10, 0xFF, 0xBC, 0x00, 0x00, 0x00, 0x7A, 0xFF, 0xFF, 0x2C, 0x00, 0x00, 0x34, 0xAD, 0xEA, 0xFA,
|
||||||
|
0xE4, 0x9F, 0x22, 0x00, 0x00, 0x00, 0x49, 0xF9, 0xFF, 0xC9, 0xA4, 0xD5, 0xFF, 0xEE, 0x2D, 0x00,
|
||||||
|
0x06, 0xE5, 0xFF, 0x6E, 0x00, 0x00, 0x02, 0x96, 0xFF, 0xC8, 0x00, 0x41, 0xFF, 0xD9, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x0D, 0xF4, 0xFF, 0x1F, 0x63, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xFF,
|
||||||
|
0x42, 0x63, 0xFF, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xFF, 0x3D, 0x3C, 0xFF, 0xDE, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x0C, 0xF4, 0xFE, 0x18, 0x04, 0xE0, 0xFF, 0x78, 0x00, 0x00, 0x01, 0x91, 0xFF,
|
||||||
|
0xB8, 0x00, 0x00, 0x44, 0xF8, 0xFF, 0xCB, 0xA4, 0xD3, 0xFF, 0xE8, 0x22, 0x00, 0x00, 0x00, 0x30,
|
||||||
|
0xAC, 0xEB, 0xF9, 0xE0, 0x95, 0x19, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0x72,
|
||||||
|
0x01, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x9F, 0xEE, 0xFF, 0x73, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00,
|
||||||
|
0x4B, 0xFF, 0xC6, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x4F, 0xFF, 0xC7, 0x10, 0xFF, 0xFA, 0x8C,
|
||||||
|
0x8C, 0x9A, 0xEE, 0xFF, 0x67, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xD8, 0x6D, 0x00, 0x10, 0xFF,
|
||||||
|
0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x32, 0xAC, 0xE9, 0xFA, 0xE4, 0x9E, 0x21, 0x00, 0x00, 0x00, 0x47, 0xF8,
|
||||||
|
0xFF, 0xCA, 0xA4, 0xD5, 0xFF, 0xED, 0x2A, 0x00, 0x05, 0xE3, 0xFF, 0x71, 0x00, 0x00, 0x02, 0x97,
|
||||||
|
0xFF, 0xC3, 0x00, 0x3F, 0xFF, 0xDB, 0x01, 0x00, 0x00, 0x00, 0x0E, 0xF5, 0xFF, 0x1B, 0x63, 0xFF,
|
||||||
|
0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xFF, 0x41, 0x64, 0xFF, 0xAC, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xD0, 0xFF, 0x3C, 0x40, 0xFF, 0xDB, 0x01, 0x00, 0x00, 0x00, 0x09, 0xF3, 0xFF, 0x19, 0x05,
|
||||||
|
0xE7, 0xFF, 0x69, 0x00, 0x00, 0x00, 0x84, 0xFF, 0xBF, 0x00, 0x00, 0x50, 0xFC, 0xFF, 0xB7, 0x90,
|
||||||
|
0xC1, 0xFF, 0xF1, 0x33, 0x00, 0x00, 0x00, 0x3F, 0xBB, 0xF5, 0xFF, 0xFC, 0xB2, 0x30, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x25, 0xFF, 0xE6, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xB5, 0xFF, 0xCB, 0x86, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xB2, 0xF4, 0xE9, 0x4C,
|
||||||
|
0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE8, 0xAF, 0x2A, 0x00, 0x10, 0xFF, 0xFA, 0x90, 0x90,
|
||||||
|
0x93, 0xC3, 0xFF, 0xE5, 0x0E, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xFF, 0x44, 0x10,
|
||||||
|
0xFF, 0xF4, 0x00, 0x00, 0x00, 0x01, 0xD2, 0xFF, 0x3E, 0x10, 0xFF, 0xFA, 0x90, 0x90, 0x92, 0xC5,
|
||||||
|
0xFF, 0xCB, 0x02, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9D, 0x0F, 0x00, 0x10, 0xFF, 0xF4,
|
||||||
|
0x00, 0x00, 0x69, 0xFF, 0xBE, 0x00, 0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x03, 0xD6, 0xFF, 0x57,
|
||||||
|
0x00, 0x10, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x4B, 0xFF, 0xE3, 0x0B, 0x10, 0xFF, 0xF4, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xBB, 0xFF, 0x87, 0x00, 0x18, 0x97, 0xDF, 0xF8, 0xEB, 0xBB, 0x3B, 0x00, 0x00, 0xC9,
|
||||||
|
0xFF, 0xA7, 0x73, 0x9D, 0xFE, 0xF3, 0x1D, 0x14, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x9A, 0xDC, 0x4F,
|
||||||
|
0x09, 0xF8, 0xFE, 0x76, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFB, 0xFF, 0xFF, 0xDD, 0x9B,
|
||||||
|
0x35, 0x00, 0x00, 0x00, 0x1E, 0x6E, 0xAC, 0xE9, 0xFF, 0xFD, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x8D, 0xFF, 0xB2, 0x56, 0xDA, 0x98, 0x00, 0x00, 0x00, 0x47, 0xFF, 0xBE, 0x1D, 0xEC, 0xFF,
|
||||||
|
0xBA, 0x8A, 0x9A, 0xEC, 0xFF, 0x65, 0x00, 0x28, 0xA3, 0xE2, 0xF9, 0xEA, 0xC2, 0x58, 0x00, 0xD8,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x68, 0x79, 0x90, 0x90, 0xE2, 0xFF, 0xAF, 0x90, 0x90,
|
||||||
|
0x3A, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC,
|
||||||
|
0xFF, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xBC, 0xFF, 0x48, 0x00, 0x00, 0x00, 0x28, 0xFF, 0xDC, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xC4, 0xFF, 0x40, 0x28, 0xFF, 0xDC, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xFF, 0x40, 0x28, 0xFF, 0xDC,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xC4, 0xFF, 0x40, 0x28, 0xFF, 0xDC, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xFF,
|
||||||
|
0x40, 0x28, 0xFF, 0xDC, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xFF, 0x40, 0x28, 0xFF, 0xDC, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xC4, 0xFF, 0x40, 0x21, 0xFF, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xFF, 0x36, 0x05,
|
||||||
|
0xF2, 0xFF, 0x3E, 0x00, 0x00, 0x34, 0xFD, 0xF7, 0x0C, 0x00, 0x81, 0xFF, 0xF6, 0xA8, 0xA9, 0xF5,
|
||||||
|
0xFF, 0x7D, 0x00, 0x00, 0x01, 0x5D, 0xCA, 0xF0, 0xF6, 0xCB, 0x61, 0x00, 0x00, 0xBB, 0xFF, 0x5A,
|
||||||
|
0x00, 0x00, 0x00, 0x09, 0xF5, 0xFC, 0x16, 0x5F, 0xFF, 0xA9, 0x00, 0x00, 0x00, 0x4D, 0xFF, 0xB7,
|
||||||
|
0x00, 0x0D, 0xF6, 0xF1, 0x06, 0x00, 0x00, 0x9B, 0xFF, 0x5C, 0x00, 0x00, 0xA9, 0xFF, 0x46, 0x00,
|
||||||
|
0x01, 0xE7, 0xF5, 0x0C, 0x00, 0x00, 0x4E, 0xFF, 0x95, 0x00, 0x37, 0xFF, 0xA6, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0xEC, 0xE2, 0x00, 0x85, 0xFF, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x97, 0xFF, 0x30, 0xD1, 0xEC,
|
||||||
|
0x05, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0x8E, 0xFF, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0xE0, 0xF7, 0xFF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xFF, 0xE0, 0x01, 0x00, 0x00,
|
||||||
|
0x00, 0xDD, 0xFF, 0x2A, 0x00, 0x00, 0x9D, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xF1, 0xFE, 0x14, 0x9D,
|
||||||
|
0xFF, 0x61, 0x00, 0x00, 0xD6, 0xFF, 0xFF, 0x1B, 0x00, 0x27, 0xFF, 0xD4, 0x00, 0x5D, 0xFF, 0x98,
|
||||||
|
0x00, 0x11, 0xFE, 0xD1, 0xFF, 0x55, 0x00, 0x5C, 0xFF, 0x94, 0x00, 0x1D, 0xFF, 0xCE, 0x00, 0x49,
|
||||||
|
0xFF, 0x6F, 0xFF, 0x8F, 0x00, 0x91, 0xFF, 0x55, 0x00, 0x00, 0xDE, 0xFB, 0x09, 0x81, 0xFF, 0x1B,
|
||||||
|
0xE8, 0xC9, 0x00, 0xC6, 0xFF, 0x16, 0x00, 0x00, 0x9F, 0xFF, 0x3C, 0xBA, 0xE2, 0x00, 0xB0, 0xFA,
|
||||||
|
0x0C, 0xF6, 0xD5, 0x00, 0x00, 0x00, 0x5F, 0xFF, 0x72, 0xEE, 0xA9, 0x00, 0x77, 0xFF, 0x65, 0xFF,
|
||||||
|
0x96, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC5, 0xFF, 0x71, 0x00, 0x3E, 0xFF, 0xC7, 0xFF, 0x56, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x38, 0x00, 0x0A, 0xFB, 0xFF, 0xFF, 0x17, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xA0, 0xFF, 0xF9, 0x07, 0x00, 0x00, 0xCC, 0xFF, 0xD7, 0x00, 0x00, 0x00, 0x46, 0xFF, 0xD1,
|
||||||
|
0x03, 0x00, 0x00, 0x7E, 0xFF, 0xA0, 0x00, 0x00, 0xA1, 0xFF, 0x70, 0x00, 0x21, 0xF7, 0xED, 0x15,
|
||||||
|
0x00, 0x00, 0x12, 0xE9, 0xF1, 0x19, 0xB4, 0xFF, 0x65, 0x00, 0x00, 0x00, 0x00, 0x57, 0xFF, 0xD4,
|
||||||
|
0xFF, 0xC5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xFF, 0xFF, 0x34, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x18, 0xEF, 0xFF, 0xFF, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xFF, 0x78, 0xF0, 0xF6,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x4B, 0xFF, 0xC3, 0x01, 0x6D, 0xFF, 0xB2, 0x00, 0x00, 0x0C, 0xE1, 0xFB,
|
||||||
|
0x2D, 0x00, 0x03, 0xCE, 0xFF, 0x4E, 0x00, 0x8F, 0xFF, 0x8D, 0x00, 0x00, 0x00, 0x37, 0xFE, 0xDF,
|
||||||
|
0x0A, 0x7B, 0xFF, 0xA4, 0x00, 0x00, 0x00, 0x4B, 0xFF, 0xD0, 0x02, 0x08, 0xDF, 0xFE, 0x38, 0x00,
|
||||||
|
0x06, 0xDA, 0xFF, 0x40, 0x00, 0x00, 0x56, 0xFF, 0xC9, 0x01, 0x78, 0xFF, 0xAE, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xC2, 0xFF, 0x77, 0xF3, 0xF9, 0x23, 0x00, 0x00, 0x00, 0x00, 0x32, 0xFD, 0xFF, 0xFF, 0x8A,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xFF, 0xEA, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x54, 0xFF, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xB0, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF,
|
||||||
|
0xB0, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x09, 0x94,
|
||||||
|
0x94, 0x94, 0x94, 0xCD, 0xFF, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xEF, 0xEE, 0x1E, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x05, 0xC8, 0xFF, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xFF, 0x91, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x4B, 0xFE, 0xCC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xEC, 0xF1, 0x23,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x03, 0xC3, 0xFF, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xFF, 0xEB,
|
||||||
|
0x94, 0x94, 0x94, 0x94, 0x94, 0x17, 0x94, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x28, 0x00,
|
||||||
|
0x03, 0xF6, 0xA6, 0x00, 0x2C, 0xFF, 0x74, 0x00, 0x5F, 0xFF, 0x42, 0x00, 0x92, 0xFF, 0x11, 0x00,
|
||||||
|
0xC5, 0xDE, 0x00, 0x02, 0xF4, 0xAC, 0x00, 0x2A, 0xFF, 0x7A, 0x00, 0x5D, 0xFF, 0x48, 0x00, 0x90,
|
||||||
|
0xFF, 0x16, 0x00, 0xC3, 0xE4, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const CoordsGlyphAA s_navTitleGlyphs[28] PROGMEM = {
|
||||||
|
{ 10, 10, 0, 0, 10, 0 }, // 'A'
|
||||||
|
{ 10, 10, 0, 0, 10, 100 }, // 'B'
|
||||||
|
{ 10, 10, 0, 0, 10, 200 }, // 'C'
|
||||||
|
{ 10, 10, 0, 0, 10, 300 }, // 'D'
|
||||||
|
{ 9, 10, 0, 0, 9, 400 }, // 'E'
|
||||||
|
{ 9, 10, 0, 0, 8, 490 }, // 'F'
|
||||||
|
{ 11, 10, 0, 0, 10, 580 }, // 'G'
|
||||||
|
{ 10, 10, 0, 0, 10, 690 }, // 'H'
|
||||||
|
{ 3, 10, 0, 0, 4, 790 }, // 'I'
|
||||||
|
{ 7, 10, 0, 0, 8, 820 }, // 'J'
|
||||||
|
{ 10, 10, 0, 0, 10, 890 }, // 'K'
|
||||||
|
{ 9, 10, 0, 0, 8, 990 }, // 'L'
|
||||||
|
{ 11, 10, 0, 0, 11, 1080 }, // 'M'
|
||||||
|
{ 10, 10, 0, 0, 10, 1190 }, // 'N'
|
||||||
|
{ 11, 10, 0, 0, 10, 1290 }, // 'O'
|
||||||
|
{ 9, 10, 0, 0, 9, 1400 }, // 'P'
|
||||||
|
{ 11, 13, 0, 0, 10, 1490 }, // 'Q'
|
||||||
|
{ 10, 10, 0, 0, 10, 1633 }, // 'R'
|
||||||
|
{ 9, 10, 0, 0, 9, 1733 }, // 'S'
|
||||||
|
{ 9, 10, 0, 0, 8, 1823 }, // 'T'
|
||||||
|
{ 10, 10, 0, 0, 10, 1913 }, // 'U'
|
||||||
|
{ 10, 10, 0, 0, 9, 2013 }, // 'V'
|
||||||
|
{ 14, 10, 0, 0, 13, 2113 }, // 'W'
|
||||||
|
{ 10, 10, 0, 0, 9, 2253 }, // 'X'
|
||||||
|
{ 10, 10, 0, 0, 9, 2353 }, // 'Y'
|
||||||
|
{ 9, 10, 0, 0, 8, 2453 }, // 'Z'
|
||||||
|
{ 4, 10, 0, 0, 4, 2543 }, // '/'
|
||||||
|
{ 0, 0, 0, 0, 4, 2583 }, // ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
// Subword Font (10.5pt Bold AA: LATITUD, LONGITUD, HDOP, MSNM, DIAGS) - 2168 bytes
|
||||||
|
static const uint8_t s_navSubAlpha[2168] PROGMEM = {
|
||||||
|
0x00, 0x00, 0x24, 0xFF, 0xFC, 0x16, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xEC, 0xF5, 0x6B, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xD4, 0xA4, 0xB3, 0xC3, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0x57, 0x66, 0xFE, 0x1C, 0x00,
|
||||||
|
0x00, 0x85, 0xFA, 0x0F, 0x19, 0xFE, 0x73, 0x00, 0x00, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0x00,
|
||||||
|
0x35, 0xFF, 0x7E, 0x30, 0x30, 0x89, 0xFF, 0x23, 0x8C, 0xF9, 0x12, 0x00, 0x00, 0x1C, 0xFD, 0x7B,
|
||||||
|
0x44, 0xFF, 0xFF, 0xFF, 0xF7, 0xD1, 0x4B, 0x00, 0x44, 0xFF, 0x71, 0x2C, 0x39, 0xD0, 0xED, 0x00,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x0C, 0xBD, 0xDB, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x46, 0x00,
|
||||||
|
0x44, 0xFF, 0x71, 0x2C, 0x33, 0x9D, 0xF7, 0x26, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x2E, 0xFF, 0x64,
|
||||||
|
0x44, 0xFF, 0x71, 0x2C, 0x31, 0x9A, 0xFF, 0x38, 0x44, 0xFF, 0xFF, 0xFF, 0xFC, 0xDC, 0x68, 0x00,
|
||||||
|
0x00, 0x21, 0xAC, 0xEF, 0xF7, 0xD6, 0x6F, 0x01, 0x05, 0xD7, 0xEA, 0x69, 0x4E, 0x85, 0xE8, 0x41,
|
||||||
|
0x53, 0xFF, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xFF, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x78, 0xFF, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xFF, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0xCE, 0xEC, 0x6A, 0x4B, 0x83, 0xE5, 0x4D, 0x00, 0x19, 0xA5, 0xED, 0xF9, 0xD9, 0x79, 0x03,
|
||||||
|
0x44, 0xFF, 0xFF, 0xFD, 0xE4, 0x96, 0x10, 0x00, 0x44, 0xFF, 0x79, 0x3E, 0x77, 0xF5, 0xCA, 0x02,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x6F, 0xFF, 0x46, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x2B, 0xFF, 0x73,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x2F, 0xFF, 0x6D, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x75, 0xFF, 0x38,
|
||||||
|
0x44, 0xFF, 0x79, 0x3A, 0x71, 0xF6, 0xBC, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0xE9, 0x96, 0x0D, 0x00,
|
||||||
|
0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB0, 0x44, 0xFF, 0x79, 0x38, 0x38, 0x38, 0x26, 0x44, 0xFF,
|
||||||
|
0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0x44, 0xFF, 0x79, 0x38,
|
||||||
|
0x38, 0x38, 0x14, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x79, 0x38, 0x38, 0x38,
|
||||||
|
0x32, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0x44,
|
||||||
|
0xFF, 0x79, 0x38, 0x38, 0x38, 0x11, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x30, 0x44, 0xFF, 0x79, 0x38, 0x38, 0x38, 0x0A, 0x44, 0xFF, 0x54, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x1A, 0xA5, 0xEB, 0xF9, 0xDF, 0x8B, 0x09, 0x03, 0xD0, 0xEE, 0x6E, 0x4B, 0x7C, 0xE6, 0x62,
|
||||||
|
0x50, 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xFF, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x78, 0xFF, 0x1C, 0x00, 0x6C, 0xFF, 0xFF, 0xE0, 0x4D, 0xFF, 0x5E, 0x00, 0x12, 0x2C, 0xA6, 0xE0,
|
||||||
|
0x02, 0xD0, 0xEF, 0x6C, 0x46, 0x6D, 0xE0, 0xD2, 0x00, 0x1B, 0xA6, 0xED, 0xF9, 0xDB, 0x8F, 0x18,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x89, 0x50, 0x50, 0x92, 0xFF, 0x34, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x60, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x54, 0x44, 0xFF, 0x54, 0x44, 0xFF, 0x54, 0x44, 0xFF, 0x54, 0x44, 0xFF, 0x54, 0x44,
|
||||||
|
0xFF, 0x54, 0x44, 0xFF, 0x54, 0x44, 0xFF, 0x54, 0x00, 0x00, 0xB8, 0xFF, 0xFF, 0x5C, 0x00, 0x00,
|
||||||
|
0x2B, 0x66, 0xFF, 0x5C, 0x00, 0x00, 0x00, 0x38, 0xFF, 0x5C, 0x00, 0x00, 0x00, 0x38, 0xFF, 0x5C,
|
||||||
|
0x00, 0x00, 0x00, 0x38, 0xFF, 0x5C, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0x54, 0x97, 0xE8, 0x54, 0x9F,
|
||||||
|
0xFC, 0x24, 0x27, 0xC6, 0xF6, 0xE3, 0x65, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x05, 0xB6, 0xED, 0x2C,
|
||||||
|
0x44, 0xFF, 0x54, 0x02, 0xA9, 0xF1, 0x34, 0x00, 0x44, 0xFF, 0x54, 0x9C, 0xF5, 0x3C, 0x00, 0x00,
|
||||||
|
0x44, 0xFF, 0xD1, 0xFF, 0x8E, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xDD, 0xB0, 0xF9, 0x35, 0x00, 0x00,
|
||||||
|
0x44, 0xFF, 0x54, 0x0B, 0xD7, 0xDF, 0x11, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x2D, 0xF7, 0xB2, 0x01,
|
||||||
|
0x44, 0xFF, 0x54, 0x00, 0x00, 0x67, 0xFF, 0x76, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44,
|
||||||
|
0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x44, 0xFF, 0x79, 0x38, 0x38, 0x38, 0x15, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
|
||||||
|
0x44, 0xFF, 0xF6, 0x09, 0x00, 0x00, 0xD5, 0xFF, 0x6C, 0x44, 0xFF, 0xEB, 0x4A, 0x00, 0x1D, 0xF6,
|
||||||
|
0xF5, 0x6C, 0x44, 0xFF, 0xB3, 0x93, 0x00, 0x66, 0xBB, 0xF9, 0x6C, 0x44, 0xFF, 0x71, 0xDD, 0x00,
|
||||||
|
0xAF, 0x74, 0xFC, 0x6C, 0x44, 0xFF, 0x2E, 0xF7, 0x2C, 0xF2, 0x29, 0xFC, 0x6C, 0x44, 0xFF, 0x24,
|
||||||
|
0xB7, 0xA5, 0xDE, 0x00, 0xFC, 0x6C, 0x44, 0xFF, 0x24, 0x6C, 0xFC, 0x93, 0x00, 0xFC, 0x6C, 0x44,
|
||||||
|
0xFF, 0x24, 0x21, 0xFF, 0x49, 0x00, 0xFC, 0x6C, 0x44, 0xFF, 0xCE, 0x01, 0x00, 0x34, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0xFE, 0x5A, 0x00, 0x34, 0xFF, 0x34, 0x44, 0xFF, 0xB4, 0xDD, 0x05, 0x34, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x3E, 0xF6, 0x6D, 0x34, 0xFF, 0x34, 0x44, 0xFF, 0x24, 0x88, 0xEA, 0x40, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x24, 0x10, 0xEE, 0xA8, 0xFF, 0x34, 0x44, 0xFF, 0x24, 0x00, 0x76, 0xFD, 0xFF, 0x34,
|
||||||
|
0x44, 0xFF, 0x24, 0x00, 0x08, 0xE3, 0xFF, 0x34, 0x00, 0x19, 0xA4, 0xEC, 0xF9, 0xD3, 0x5F, 0x00,
|
||||||
|
0x00, 0x02, 0xCE, 0xEF, 0x6D, 0x4E, 0xAA, 0xFF, 0x64, 0x00, 0x4E, 0xFF, 0x5C, 0x00, 0x00, 0x01,
|
||||||
|
0xD3, 0xDF, 0x00, 0x7A, 0xFF, 0x1B, 0x00, 0x00, 0x00, 0x93, 0xFF, 0x0E, 0x82, 0xFF, 0x1D, 0x00,
|
||||||
|
0x00, 0x00, 0x95, 0xFF, 0x0A, 0x50, 0xFF, 0x62, 0x00, 0x00, 0x01, 0xD4, 0xD6, 0x00, 0x04, 0xD0,
|
||||||
|
0xF1, 0x6F, 0x4E, 0xAA, 0xFF, 0x58, 0x00, 0x00, 0x15, 0xA0, 0xEC, 0xF7, 0xCD, 0x55, 0x00, 0x00,
|
||||||
|
0x44, 0xFF, 0xFF, 0xFF, 0xF3, 0xBB, 0x24, 0x44, 0xFF, 0x7C, 0x3C, 0x57, 0xED, 0xC1, 0x44, 0xFF,
|
||||||
|
0x54, 0x00, 0x00, 0xAE, 0xEE, 0x44, 0xFF, 0x79, 0x38, 0x54, 0xEF, 0xBA, 0x44, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xF8, 0xBA, 0x1E, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA3, 0xEC, 0xF9, 0xD2, 0x5D, 0x00,
|
||||||
|
0x00, 0x02, 0xCB, 0xF0, 0x6E, 0x4F, 0xAC, 0xFF, 0x60, 0x00, 0x4D, 0xFF, 0x5E, 0x00, 0x00, 0x01,
|
||||||
|
0xD5, 0xDB, 0x00, 0x79, 0xFF, 0x1C, 0x00, 0x00, 0x00, 0x94, 0xFF, 0x0D, 0x7B, 0xFF, 0x1B, 0x00,
|
||||||
|
0x00, 0x00, 0x94, 0xFE, 0x09, 0x4F, 0xFF, 0x5D, 0x00, 0x00, 0x00, 0xD0, 0xDB, 0x00, 0x03, 0xD4,
|
||||||
|
0xEC, 0x60, 0x3E, 0x9D, 0xFF, 0x64, 0x00, 0x00, 0x15, 0xA6, 0xF0, 0xFF, 0xE5, 0x6E, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x20, 0xFC, 0xB4, 0x38, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xE9, 0xF2,
|
||||||
|
0x4D, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0xFB, 0xDA, 0x60, 0x00, 0x44, 0xFF, 0x7C, 0x3C, 0x42, 0xB4,
|
||||||
|
0xFD, 0x26, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x4A, 0xFF, 0x4D, 0x44, 0xFF, 0x7C, 0x3C, 0x42, 0xB9,
|
||||||
|
0xF8, 0x1A, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x40, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x89, 0xFC,
|
||||||
|
0x30, 0x00, 0x44, 0xFF, 0x54, 0x00, 0x0C, 0xE5, 0xC8, 0x02, 0x44, 0xFF, 0x54, 0x00, 0x00, 0x5B,
|
||||||
|
0xFF, 0x68, 0x00, 0x65, 0xD8, 0xF8, 0xED, 0xAC, 0x13, 0x2C, 0xFF, 0x8D, 0x27, 0x54, 0xEF, 0x77,
|
||||||
|
0x47, 0xFF, 0x73, 0x00, 0x00, 0x00, 0x00, 0x08, 0xCC, 0xFF, 0xE3, 0xA3, 0x51, 0x00, 0x00, 0x03,
|
||||||
|
0x48, 0x8A, 0xD2, 0xFF, 0x88, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC3, 0xDA, 0x6B, 0xED, 0x68, 0x34,
|
||||||
|
0x4F, 0xE7, 0xB2, 0x0A, 0x92, 0xE3, 0xF9, 0xE9, 0xA8, 0x1A, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x98, 0x31, 0x38, 0x8F, 0xFF, 0x57, 0x38, 0x21, 0x00, 0x00, 0x70, 0xFF, 0x28, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x70, 0xFF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x70,
|
||||||
|
0xFF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x28,
|
||||||
|
0x00, 0x00, 0x58, 0xFF, 0x40, 0x00, 0x00, 0x50, 0xFF, 0x44, 0x58, 0xFF, 0x40, 0x00, 0x00, 0x50,
|
||||||
|
0xFF, 0x44, 0x58, 0xFF, 0x40, 0x00, 0x00, 0x50, 0xFF, 0x44, 0x58, 0xFF, 0x40, 0x00, 0x00, 0x50,
|
||||||
|
0xFF, 0x44, 0x57, 0xFF, 0x40, 0x00, 0x00, 0x50, 0xFF, 0x43, 0x41, 0xFF, 0x5A, 0x00, 0x00, 0x6F,
|
||||||
|
0xFF, 0x27, 0x0D, 0xE7, 0xD9, 0x51, 0x5A, 0xE6, 0xCE, 0x02, 0x00, 0x32, 0xBF, 0xF1, 0xE9, 0xA9,
|
||||||
|
0x1D, 0x00, 0xC0, 0xE1, 0x00, 0x00, 0x00, 0x87, 0xFD, 0x19, 0x66, 0xFF, 0x2F, 0x00, 0x00, 0xD3,
|
||||||
|
0xBD, 0x00, 0x12, 0xFA, 0x7C, 0x00, 0x1F, 0xFF, 0x64, 0x00, 0x00, 0xB3, 0xC9, 0x00, 0x6C, 0xFA,
|
||||||
|
0x11, 0x00, 0x00, 0x5A, 0xFE, 0x18, 0xB8, 0xB2, 0x00, 0x00, 0x00, 0x0B, 0xF5, 0x6A, 0xF8, 0x59,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xA7, 0xE0, 0xF5, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xFF, 0xA8, 0x00,
|
||||||
|
0x00, 0x00, 0xDE, 0xB4, 0x00, 0x00, 0xC7, 0xFF, 0x32, 0x00, 0x55, 0xFF, 0x40, 0xA0, 0xE7, 0x00,
|
||||||
|
0x05, 0xF7, 0xF7, 0x67, 0x00, 0x85, 0xF9, 0x08, 0x62, 0xFF, 0x1A, 0x31, 0xFC, 0xAE, 0x9D, 0x00,
|
||||||
|
0xB6, 0xC3, 0x00, 0x24, 0xFF, 0x4C, 0x66, 0xD0, 0x74, 0xD2, 0x00, 0xE7, 0x84, 0x00, 0x00, 0xE5,
|
||||||
|
0x7F, 0x9A, 0x99, 0x3D, 0xFC, 0x22, 0xFF, 0x46, 0x00, 0x00, 0xA8, 0xB1, 0xCB, 0x62, 0x09, 0xFB,
|
||||||
|
0x82, 0xFB, 0x0C, 0x00, 0x00, 0x6A, 0xE4, 0xF6, 0x2A, 0x00, 0xCD, 0xDD, 0xC9, 0x00, 0x00, 0x00,
|
||||||
|
0x2B, 0xFF, 0xF1, 0x02, 0x00, 0x94, 0xFF, 0x8B, 0x00, 0x00, 0x5F, 0xFF, 0x4B, 0x00, 0x0C, 0xE4,
|
||||||
|
0xB6, 0x00, 0x00, 0xBC, 0xDB, 0x07, 0x89, 0xF7, 0x23, 0x00, 0x00, 0x23, 0xF6, 0x9D, 0xFA, 0x80,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE3, 0x08, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xFA, 0xFA, 0x28,
|
||||||
|
0x00, 0x00, 0x00, 0x59, 0xFF, 0x4D, 0xE1, 0xBC, 0x00, 0x00, 0x10, 0xE8, 0xA9, 0x00, 0x52, 0xFF,
|
||||||
|
0x55, 0x00, 0x98, 0xF4, 0x1C, 0x00, 0x00, 0xB8, 0xE3, 0x0B, 0x8B, 0xF8, 0x18, 0x00, 0x00, 0xBC,
|
||||||
|
0xDD, 0x05, 0x11, 0xEF, 0x85, 0x00, 0x31, 0xFF, 0x59, 0x00, 0x00, 0x76, 0xED, 0x0B, 0xA8, 0xCE,
|
||||||
|
0x01, 0x00, 0x00, 0x08, 0xE3, 0x8E, 0xFC, 0x46, 0x00, 0x00, 0x00, 0x00, 0x61, 0xFF, 0xBC, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0x78, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0x78, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x30, 0x0F, 0x3C, 0x3C, 0x3F, 0xE0, 0xD9, 0x0A, 0x00, 0x00, 0x00, 0x80, 0xF9, 0x32, 0x00, 0x00,
|
||||||
|
0x00, 0x3C, 0xFC, 0x73, 0x00, 0x00, 0x00, 0x11, 0xE1, 0xB9, 0x01, 0x00, 0x00, 0x00, 0xAC, 0xE9,
|
||||||
|
0x18, 0x00, 0x00, 0x00, 0x65, 0xFF, 0x84, 0x3C, 0x3C, 0x3C, 0x18, 0xAC, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0x68, 0x00, 0x73, 0xEB, 0xE8, 0x7C, 0x00, 0x2B, 0xFF, 0x78, 0x65, 0xFF, 0x3B, 0x70, 0xFE,
|
||||||
|
0x07, 0x00, 0xF0, 0x87, 0x89, 0xF3, 0x00, 0x00, 0xDB, 0xA0, 0x85, 0xF2, 0x00, 0x00, 0xDC, 0x9F,
|
||||||
|
0x6A, 0xFE, 0x07, 0x00, 0xF0, 0x84, 0x1E, 0xFD, 0x78, 0x68, 0xFF, 0x34, 0x00, 0x62, 0xE2, 0xF0,
|
||||||
|
0x7E, 0x00, 0x0F, 0x82, 0xE9, 0xFF, 0x14, 0x00, 0x3C, 0xB4, 0xA8, 0xFF, 0x14, 0x00, 0x00, 0x00,
|
||||||
|
0x70, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x70, 0xFF, 0x14, 0x00,
|
||||||
|
0x00, 0x00, 0x70, 0xFF, 0x14, 0x00, 0x0A, 0x20, 0x82, 0xFF, 0x31, 0x1A, 0x50, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xD0, 0x06, 0x9B, 0xEF, 0xEE, 0xA0, 0x06, 0x60, 0xF9, 0x6B, 0x60, 0xFF, 0x69, 0x00, 0x00,
|
||||||
|
0x00, 0x0B, 0xFE, 0x7E, 0x00, 0x00, 0x01, 0x9F, 0xFC, 0x2F, 0x00, 0x06, 0xA8, 0xFD, 0x63, 0x00,
|
||||||
|
0x00, 0xAB, 0xF5, 0x4B, 0x00, 0x00, 0x5C, 0xFF, 0x8F, 0x3C, 0x3C, 0x28, 0xA0, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xAC, 0x09, 0xA0, 0xEF, 0xF0, 0xA9, 0x0B, 0x6F, 0xF7, 0x60, 0x69, 0xFF, 0x71, 0x00, 0x00,
|
||||||
|
0x01, 0x39, 0xFF, 0x5E, 0x00, 0x00, 0xCC, 0xFE, 0x92, 0x01, 0x00, 0x00, 0x2D, 0x6D, 0xFD, 0x64,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0x8D, 0xF0, 0x5A, 0x5E, 0xFC, 0x83, 0x15, 0xAF, 0xF1, 0xEF,
|
||||||
|
0xA6, 0x0C, 0x00, 0x00, 0x0F, 0xE6, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x99, 0xE7, 0xFF, 0x0C, 0x00,
|
||||||
|
0x00, 0x3D, 0xE9, 0x77, 0xFF, 0x0C, 0x00, 0x07, 0xD7, 0x5A, 0x64, 0xFF, 0x0C, 0x00, 0x82, 0xB6,
|
||||||
|
0x00, 0x64, 0xFF, 0x0C, 0x00, 0xD4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x1A, 0x20, 0x20, 0x77,
|
||||||
|
0xFF, 0x2A, 0x02, 0x00, 0x00, 0x00, 0x64, 0xFF, 0x0C, 0x00, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0x60,
|
||||||
|
0x42, 0xFF, 0x44, 0x20, 0x20, 0x0C, 0x50, 0xFF, 0x1D, 0x00, 0x00, 0x00, 0x5F, 0xFF, 0xC9, 0xF5,
|
||||||
|
0xBB, 0x19, 0x4B, 0xB4, 0x68, 0x58, 0xF7, 0x9D, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC4, 0x75, 0xF4,
|
||||||
|
0x5F, 0x56, 0xF7, 0x8E, 0x0C, 0xA5, 0xF1, 0xED, 0xA2, 0x0D, 0x00, 0x55, 0xE2, 0xF5, 0xA5, 0x06,
|
||||||
|
0x1E, 0xF9, 0x91, 0x5A, 0xEE, 0x4D, 0x6D, 0xFA, 0x0B, 0x00, 0x00, 0x00, 0x8F, 0xED, 0xAB, 0xF2,
|
||||||
|
0xBC, 0x15, 0x8E, 0xFF, 0x5C, 0x3F, 0xF7, 0x8B, 0x72, 0xFF, 0x06, 0x00, 0xD4, 0xAD, 0x22, 0xFD,
|
||||||
|
0x80, 0x4E, 0xFA, 0x7B, 0x00, 0x5B, 0xDE, 0xF1, 0xA4, 0x0A, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xA4,
|
||||||
|
0x1F, 0x3C, 0x3C, 0x47, 0xF4, 0x72, 0x00, 0x00, 0x00, 0x8D, 0xDB, 0x06, 0x00, 0x00, 0x25, 0xFB,
|
||||||
|
0x5C, 0x00, 0x00, 0x00, 0x9A, 0xE1, 0x03, 0x00, 0x00, 0x08, 0xF0, 0x8C, 0x00, 0x00, 0x00, 0x3B,
|
||||||
|
0xFF, 0x4C, 0x00, 0x00, 0x00, 0x5C, 0xFF, 0x31, 0x00, 0x00, 0x06, 0x9F, 0xEE, 0xF2, 0xB3, 0x12,
|
||||||
|
0x60, 0xFF, 0x5A, 0x3B, 0xFE, 0x81, 0x4F, 0xFF, 0x4E, 0x23, 0xFD, 0x6F, 0x00, 0xA5, 0xFF, 0xFF,
|
||||||
|
0xBE, 0x04, 0x5C, 0xFE, 0x44, 0x32, 0xF4, 0x7F, 0x9E, 0xEE, 0x00, 0x00, 0xCF, 0xBE, 0x74, 0xFE,
|
||||||
|
0x44, 0x2F, 0xF4, 0x93, 0x07, 0x9B, 0xEC, 0xF0, 0xAC, 0x12, 0x04, 0x96, 0xEC, 0xE6, 0x7A, 0x00,
|
||||||
|
0x68, 0xFF, 0x63, 0x6D, 0xFF, 0x40, 0x96, 0xEF, 0x00, 0x00, 0xEE, 0x8F, 0x70, 0xFF, 0x53, 0x51,
|
||||||
|
0xFD, 0xA9, 0x0A, 0xAF, 0xF3, 0xC0, 0xDE, 0xAB, 0x00, 0x00, 0x00, 0x02, 0xEC, 0x8A, 0x47, 0xEE,
|
||||||
|
0x61, 0x80, 0xFF, 0x38, 0x04, 0xA1, 0xF4, 0xE9, 0x6D, 0x00, 0xF0, 0x9C, 0xF0, 0x9C, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xF0, 0x9C, 0xF0, 0x9C, 0x40, 0xFF, 0x4C, 0x40, 0xFF, 0x4C, 0x90, 0xFF, 0xFF, 0x38,
|
||||||
|
0x2D, 0x50, 0x50, 0x11, 0x1F, 0xC5, 0xD7, 0x68, 0x74, 0x6B, 0x0C, 0xD9, 0x22, 0xCC, 0xD8, 0x69,
|
||||||
|
0x00, 0x6E, 0xDA, 0x00, 0xA0, 0xA9, 0x00, 0xD2, 0x78, 0x08, 0xFB, 0x47, 0x36, 0xFF, 0x17, 0x68,
|
||||||
|
0xE5, 0x00, 0x9A, 0xB4, 0x00, 0xCB, 0x84, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const CoordsGlyphAA s_navSubGlyphs[42] PROGMEM = {
|
||||||
|
{ 8, 8, 0, 0, 8, 0 }, // 'A'
|
||||||
|
{ 8, 8, 0, 0, 8, 64 }, // 'B'
|
||||||
|
{ 8, 8, 0, 0, 8, 128 }, // 'C'
|
||||||
|
{ 8, 8, 0, 0, 8, 192 }, // 'D'
|
||||||
|
{ 7, 8, 0, 0, 7, 256 }, // 'E'
|
||||||
|
{ 7, 8, 0, 0, 6, 312 }, // 'F'
|
||||||
|
{ 8, 8, 0, 0, 8, 368 }, // 'G'
|
||||||
|
{ 8, 8, 0, 0, 8, 432 }, // 'H'
|
||||||
|
{ 3, 8, 0, 0, 3, 496 }, // 'I'
|
||||||
|
{ 6, 8, 0, 0, 6, 520 }, // 'J'
|
||||||
|
{ 8, 8, 0, 0, 8, 568 }, // 'K'
|
||||||
|
{ 7, 8, 0, 0, 6, 632 }, // 'L'
|
||||||
|
{ 9, 8, 0, 0, 9, 688 }, // 'M'
|
||||||
|
{ 8, 8, 0, 0, 8, 760 }, // 'N'
|
||||||
|
{ 9, 8, 0, 0, 8, 824 }, // 'O'
|
||||||
|
{ 7, 8, 0, 0, 7, 896 }, // 'P'
|
||||||
|
{ 9, 10, 0, 0, 8, 952 }, // 'Q'
|
||||||
|
{ 8, 8, 0, 0, 8, 1042 }, // 'R'
|
||||||
|
{ 7, 8, 0, 0, 7, 1106 }, // 'S'
|
||||||
|
{ 7, 8, 0, 0, 6, 1162 }, // 'T'
|
||||||
|
{ 8, 8, 0, 0, 8, 1218 }, // 'U'
|
||||||
|
{ 8, 8, 0, 0, 7, 1282 }, // 'V'
|
||||||
|
{ 11, 8, 0, 0, 10, 1346 }, // 'W'
|
||||||
|
{ 8, 8, 0, 0, 7, 1434 }, // 'X'
|
||||||
|
{ 8, 8, 0, 0, 7, 1498 }, // 'Y'
|
||||||
|
{ 7, 8, 0, 0, 6, 1562 }, // 'Z'
|
||||||
|
{ 6, 8, 0, 0, 6, 1618 }, // '0'
|
||||||
|
{ 6, 8, 0, 0, 6, 1666 }, // '1'
|
||||||
|
{ 6, 8, 0, 0, 6, 1714 }, // '2'
|
||||||
|
{ 6, 8, 0, 0, 6, 1762 }, // '3'
|
||||||
|
{ 7, 8, 0, 0, 6, 1810 }, // '4'
|
||||||
|
{ 6, 8, 0, 0, 6, 1866 }, // '5'
|
||||||
|
{ 6, 8, 0, 0, 6, 1914 }, // '6'
|
||||||
|
{ 6, 8, 0, 0, 6, 1962 }, // '7'
|
||||||
|
{ 6, 8, 0, 0, 6, 2010 }, // '8'
|
||||||
|
{ 6, 8, 0, 0, 6, 2058 }, // '9'
|
||||||
|
{ 2, 6, 1, 2, 4, 2106 }, // ':'
|
||||||
|
{ 3, 2, 0, 6, 3, 2118 }, // '.'
|
||||||
|
{ 4, 2, 0, 4, 4, 2124 }, // '-'
|
||||||
|
{ 4, 3, 0, 0, 4, 2132 }, // '°'
|
||||||
|
{ 3, 8, 0, 0, 3, 2144 }, // '/'
|
||||||
|
{ 0, 0, 0, 0, 3, 2168 }, // ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
// Coordinates Value Font (20pt Bold AA: Digits, Sign, Dot, Degree) - 1618 bytes
|
||||||
|
static const uint8_t s_coordsValueAlpha[1618] PROGMEM = {
|
||||||
|
0x00, 0x00, 0x13, 0x8E, 0xDD, 0xF8, 0xE6, 0x9D, 0x18, 0x00, 0x00, 0x00, 0x0A, 0xCF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xDD, 0x11, 0x00, 0x00, 0x71, 0xFF, 0xFF, 0x8A, 0x32, 0x79, 0xFF, 0xFF, 0x86,
|
||||||
|
0x00, 0x00, 0xCB, 0xFF, 0xDE, 0x01, 0x00, 0x00, 0xCF, 0xFF, 0xE1, 0x00, 0x07, 0xFA, 0xFF, 0xA8,
|
||||||
|
0x00, 0x00, 0x00, 0x98, 0xFF, 0xFF, 0x18, 0x1E, 0xFF, 0xFF, 0x92, 0x00, 0x00, 0x00, 0x80, 0xFF,
|
||||||
|
0xFF, 0x38, 0x2D, 0xFF, 0xFF, 0x8B, 0x00, 0x00, 0x00, 0x78, 0xFF, 0xFF, 0x46, 0x2F, 0xFF, 0xFF,
|
||||||
|
0x8B, 0x00, 0x00, 0x00, 0x78, 0xFF, 0xFF, 0x45, 0x22, 0xFF, 0xFF, 0x93, 0x00, 0x00, 0x00, 0x81,
|
||||||
|
0xFF, 0xFF, 0x37, 0x04, 0xFA, 0xFF, 0xAC, 0x00, 0x00, 0x00, 0x9A, 0xFF, 0xFF, 0x14, 0x00, 0xC6,
|
||||||
|
0xFF, 0xE2, 0x01, 0x00, 0x00, 0xD4, 0xFF, 0xD9, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x8C, 0x32, 0x82,
|
||||||
|
0xFF, 0xFF, 0x79, 0x00, 0x00, 0x05, 0xC6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0x0A, 0x00, 0x00,
|
||||||
|
0x00, 0x0C, 0x8C, 0xE1, 0xF9, 0xE3, 0x91, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xD3, 0xFF, 0xFF,
|
||||||
|
0x68, 0x00, 0x00, 0x00, 0x36, 0xC4, 0xFF, 0xFF, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0xA0, 0xFF,
|
||||||
|
0xE6, 0xAC, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x87, 0x70, 0x08, 0x54, 0xFF, 0xFF, 0x68, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
|
||||||
|
0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x54, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xFF,
|
||||||
|
0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x54, 0xFF, 0xFF, 0x68, 0x00, 0x00, 0x00, 0x08, 0x0C, 0x0C, 0x5C, 0xFF, 0xFF, 0x6F, 0x0C,
|
||||||
|
0x0C, 0x06, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x90, 0xBC, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x90, 0x00, 0x00, 0x2A, 0xA6, 0xDD, 0xF9, 0xEB, 0xB6, 0x42, 0x00,
|
||||||
|
0x00, 0x00, 0x33, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x57, 0x00, 0x00, 0xCB, 0xFF, 0xFF,
|
||||||
|
0x79, 0x39, 0x72, 0xFE, 0xFF, 0xE0, 0x00, 0x0F, 0xE1, 0xF1, 0xB7, 0x00, 0x00, 0x00, 0xC0, 0xFF,
|
||||||
|
0xFF, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xFF, 0xFE, 0x0A, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x4B, 0xFF, 0xFF, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0xF4, 0xFF,
|
||||||
|
0xF8, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFA, 0xFF, 0xF9, 0x52, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x80, 0xFF, 0xFF, 0xED, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xFF, 0xFF, 0xD7, 0x22,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xFF, 0xFF, 0xCA, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
|
||||||
|
0xEC, 0xFF, 0xFF, 0x5E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x15, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x54,
|
||||||
|
0x00, 0x00, 0x37, 0xAF, 0xEA, 0xF9, 0xDE, 0xAA, 0x32, 0x00, 0x00, 0x00, 0x51, 0xFC, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFD, 0x51, 0x00, 0x07, 0xEB, 0xFF, 0xF8, 0x6B, 0x3A, 0x87, 0xFF, 0xFF, 0xDA,
|
||||||
|
0x00, 0x30, 0xDB, 0xEE, 0x91, 0x00, 0x00, 0x00, 0xD4, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xD6, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x32, 0x91, 0xFF, 0xFF,
|
||||||
|
0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC8, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0xFF, 0xFF, 0xF5, 0xAE, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x27, 0x62, 0xF1,
|
||||||
|
0xFF, 0xDF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x4D, 0x5F, 0xDA,
|
||||||
|
0xEF, 0x69, 0x00, 0x00, 0x00, 0x87, 0xFF, 0xFF, 0x5D, 0x33, 0xFF, 0xFF, 0xF0, 0x6D, 0x44, 0x6E,
|
||||||
|
0xF3, 0xFF, 0xFE, 0x26, 0x00, 0x8D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x91, 0x00, 0x00,
|
||||||
|
0x00, 0x46, 0xB5, 0xE0, 0xFA, 0xEF, 0xBF, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39,
|
||||||
|
0xFD, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xD5, 0xFF, 0xFF, 0xFF, 0x30,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xFF, 0xF1, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x2D, 0xFA, 0xF6, 0x89, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0xCA, 0xFF, 0x78,
|
||||||
|
0x6F, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x73, 0xFF, 0xCD, 0x04, 0x70, 0xFF, 0xFF, 0x30,
|
||||||
|
0x00, 0x00, 0x00, 0x22, 0xF5, 0xFB, 0x30, 0x00, 0x70, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0xBD,
|
||||||
|
0xFF, 0x85, 0x00, 0x00, 0x70, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x63, 0xFF, 0xD7, 0x07, 0x00, 0x00,
|
||||||
|
0x70, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0x04, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x08, 0x0C,
|
||||||
|
0x0C, 0x0C, 0x0C, 0x0C, 0x76, 0xFF, 0xFF, 0x39, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x70, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xFF, 0xFF, 0x30,
|
||||||
|
0x00, 0x00, 0x00, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC4, 0x00, 0x00, 0x97, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC4, 0x00, 0x00, 0xA6, 0xFF, 0xF5, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||||
|
0x0C, 0x09, 0x00, 0x00, 0xB6, 0xFF, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5,
|
||||||
|
0xFF, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xFF, 0xD4, 0x8D, 0xE0, 0xF8,
|
||||||
|
0xD6, 0x73, 0x02, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA0, 0x00, 0x00,
|
||||||
|
0xF3, 0xFF, 0xFC, 0x86, 0x44, 0x71, 0xF3, 0xFF, 0xFF, 0x35, 0x00, 0x1B, 0x1C, 0x15, 0x00, 0x00,
|
||||||
|
0x00, 0x77, 0xFF, 0xFF, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xFF, 0xFF, 0x8A,
|
||||||
|
0x35, 0xD7, 0xED, 0x8A, 0x00, 0x00, 0x00, 0x78, 0xFF, 0xFF, 0x6D, 0x07, 0xF0, 0xFF, 0xF9, 0x6D,
|
||||||
|
0x35, 0x69, 0xF2, 0xFF, 0xF9, 0x1E, 0x00, 0x51, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x69,
|
||||||
|
0x00, 0x00, 0x00, 0x36, 0xAE, 0xE0, 0xFA, 0xEA, 0xB0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x02, 0x69,
|
||||||
|
0xCF, 0xF6, 0xE8, 0xB1, 0x2D, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
||||||
|
0x23, 0x00, 0x00, 0x51, 0xFF, 0xFF, 0xB3, 0x3A, 0x6F, 0xFF, 0xFF, 0xA3, 0x00, 0x00, 0xBC, 0xFF,
|
||||||
|
0xE8, 0x09, 0x00, 0x00, 0xB3, 0xD6, 0xA2, 0x00, 0x05, 0xFA, 0xFF, 0x9D, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x28, 0xFF, 0xFF, 0x7C, 0x7D, 0xE0, 0xF9, 0xDB, 0x74, 0x01, 0x00, 0x3A, 0xFF,
|
||||||
|
0xFF, 0xE5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x40, 0xFF, 0xFF, 0xFE, 0x61, 0x10, 0x43,
|
||||||
|
0xED, 0xFF, 0xFC, 0x1B, 0x34, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x00, 0x83, 0xFF, 0xFF, 0x54, 0x12,
|
||||||
|
0xFF, 0xFF, 0xA9, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0x62, 0x00, 0xD6, 0xFF, 0xE2, 0x04, 0x00,
|
||||||
|
0x00, 0x8F, 0xFF, 0xFF, 0x48, 0x00, 0x71, 0xFF, 0xFF, 0xA3, 0x34, 0x60, 0xF5, 0xFF, 0xEF, 0x0C,
|
||||||
|
0x00, 0x05, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5F, 0x00, 0x00, 0x00, 0x08, 0x7B, 0xD6,
|
||||||
|
0xF8, 0xF1, 0xBC, 0x45, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x40, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x09, 0x40, 0x40, 0x40,
|
||||||
|
0x40, 0x40, 0x40, 0xA9, 0xFF, 0xF2, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF7, 0xFF,
|
||||||
|
0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC3, 0xFF, 0xD1, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x63, 0xFF, 0xFF, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xEA, 0xFF, 0xC2,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x07, 0xE8, 0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0x84,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xFF, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xDF, 0xFF, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xFF, 0xFF, 0xCF,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x3A, 0xB1, 0xEA, 0xFB, 0xEE, 0xBB, 0x4E, 0x00, 0x00, 0x00, 0x4B, 0xFC, 0xFF, 0xFF,
|
||||||
|
0xF6, 0xFF, 0xFF, 0xFF, 0x6B, 0x00, 0x00, 0xD5, 0xFF, 0xFD, 0x44, 0x00, 0x2F, 0xF4, 0xFF, 0xF0,
|
||||||
|
0x05, 0x04, 0xFF, 0xFF, 0xD1, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0x23, 0x00, 0xED, 0xFF, 0xD7,
|
||||||
|
0x00, 0x00, 0x00, 0xBA, 0xFF, 0xFE, 0x0F, 0x00, 0x85, 0xFF, 0xFF, 0x5C, 0x0A, 0x43, 0xF9, 0xFF,
|
||||||
|
0xA4, 0x00, 0x00, 0x02, 0x83, 0xEF, 0xFF, 0xFF, 0xFF, 0xF5, 0x94, 0x09, 0x00, 0x00, 0x1E, 0xB2,
|
||||||
|
0xF9, 0xFF, 0xF5, 0xFF, 0xFE, 0xC9, 0x36, 0x00, 0x06, 0xD9, 0xFF, 0xE4, 0x29, 0x00, 0x1D, 0xCE,
|
||||||
|
0xFF, 0xF2, 0x1A, 0x40, 0xFF, 0xFF, 0x85, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0x69, 0x53, 0xFF,
|
||||||
|
0xFF, 0x88, 0x00, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x7A, 0x20, 0xFD, 0xFF, 0xE5, 0x2C, 0x00, 0x1C,
|
||||||
|
0xD0, 0xFF, 0xFF, 0x44, 0x00, 0x88, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xAE, 0x00, 0x00,
|
||||||
|
0x00, 0x54, 0xBA, 0xEC, 0xFC, 0xF1, 0xC5, 0x69, 0x03, 0x00, 0x00, 0x00, 0x37, 0xAF, 0xE9, 0xFA,
|
||||||
|
0xE3, 0x9A, 0x18, 0x00, 0x00, 0x00, 0x50, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x17, 0x00,
|
||||||
|
0x04, 0xE6, 0xFF, 0xFD, 0x74, 0x36, 0x8F, 0xFF, 0xFF, 0x98, 0x00, 0x35, 0xFF, 0xFF, 0xAC, 0x00,
|
||||||
|
0x00, 0x00, 0xC9, 0xFF, 0xF1, 0x06, 0x4B, 0xFF, 0xFF, 0x84, 0x00, 0x00, 0x00, 0x90, 0xFF, 0xFF,
|
||||||
|
0x2E, 0x39, 0xFF, 0xFF, 0xA6, 0x00, 0x00, 0x00, 0xA6, 0xFF, 0xFF, 0x4F, 0x09, 0xF1, 0xFF, 0xFA,
|
||||||
|
0x59, 0x17, 0x5F, 0xFB, 0xFF, 0xFF, 0x5B, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF,
|
||||||
|
0xFF, 0x56, 0x00, 0x00, 0x65, 0xD6, 0xF9, 0xE3, 0x89, 0x68, 0xFF, 0xFF, 0x45, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x87, 0xFF, 0xFF, 0x1D, 0x01, 0xA6, 0xD6, 0xA7, 0x00, 0x00, 0x03, 0xD8,
|
||||||
|
0xFF, 0xD9, 0x00, 0x00, 0xAC, 0xFF, 0xFD, 0x69, 0x33, 0xA3, 0xFF, 0xFF, 0x6F, 0x00, 0x00, 0x29,
|
||||||
|
0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x30, 0xB2, 0xE8, 0xF8, 0xD6,
|
||||||
|
0x78, 0x06, 0x00, 0x00, 0xA4, 0xFF, 0xFF, 0x30, 0xA4, 0xFF, 0xFF, 0x30, 0xA4, 0xFF, 0xFF, 0x30,
|
||||||
|
0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0x15, 0x64, 0x64, 0x64,
|
||||||
|
0x64, 0x55, 0x00, 0x0D, 0x98, 0xEE, 0xE8, 0x94, 0x0C, 0x00, 0x00, 0xAC, 0xF9, 0x93, 0x93, 0xFA,
|
||||||
|
0xA8, 0x00, 0x0F, 0xFE, 0x86, 0x00, 0x00, 0x8A, 0xFD, 0x0C, 0x0A, 0xFC, 0x86, 0x00, 0x00, 0x8B,
|
||||||
|
0xFD, 0x0C, 0x00, 0xA6, 0xF9, 0x8F, 0x90, 0xFA, 0xA7, 0x00, 0x00, 0x0C, 0x94, 0xE9, 0xE9, 0x95,
|
||||||
|
0x0C, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const CoordsGlyphAA s_coordsValueGlyphs[14] PROGMEM = {
|
||||||
|
{ 11, 14, 0, 0, 11, 0 }, // '0'
|
||||||
|
{ 10, 14, 1, 0, 11, 154 }, // '1'
|
||||||
|
{ 11, 14, 0, 0, 11, 294 }, // '2'
|
||||||
|
{ 11, 14, 0, 0, 11, 448 }, // '3'
|
||||||
|
{ 12, 14, 0, 0, 11, 602 }, // '4'
|
||||||
|
{ 11, 14, 0, 0, 11, 770 }, // '5'
|
||||||
|
{ 11, 14, 0, 0, 11, 924 }, // '6'
|
||||||
|
{ 11, 14, 0, 0, 11, 1078 }, // '7'
|
||||||
|
{ 11, 14, 0, 0, 11, 1232 }, // '8'
|
||||||
|
{ 11, 14, 0, 0, 11, 1386 }, // '9'
|
||||||
|
{ 4, 3, 1, 11, 6, 1540 }, // '.'
|
||||||
|
{ 6, 3, 0, 8, 7, 1552 }, // '-'
|
||||||
|
{ 8, 6, 0, 0, 8, 1570 }, // '°'
|
||||||
|
{ 0, 0, 0, 0, 6, 1618 }, // ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
// Draw single anti-aliased character glyph
|
||||||
|
template <typename T>
|
||||||
|
inline void drawCoordsAAChar(T &dst, int x0, int y0, const CoordsGlyphAA &g, const uint8_t *alphaTable, uint16_t color, uint16_t bgCol, int clip_h) {
|
||||||
|
if (g.w == 0 || g.h == 0) return;
|
||||||
|
for (uint8_t dy = 0; dy < g.h; dy++) {
|
||||||
|
int curY = y0 + g.yOff + dy;
|
||||||
|
if (curY < 0 || curY >= clip_h) continue;
|
||||||
|
uint32_t rowStart = g.offset + (uint32_t)dy * g.w;
|
||||||
|
for (uint8_t dx = 0; dx < g.w; dx++) {
|
||||||
|
int curX = x0 + g.xOff + dx;
|
||||||
|
if (curX < 0 || curX >= dst.width()) continue;
|
||||||
|
uint8_t a = pgm_read_byte(&alphaTable[rowStart + dx]);
|
||||||
|
if (a > 6) {
|
||||||
|
uint16_t pixCol = (a >= 250) ? color : fastBlend(a, color, bgCol);
|
||||||
|
dst.drawPixel(curX, curY, pixCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Draw 100% anti-aliased Title (ALTITUD, RUMBO / BRUJULA, SATELITES GPS, COORDENADAS)
|
||||||
|
template <typename T>
|
||||||
|
inline void drawGpsNavTitle(T &dst, const char *str, int x, int y, uint16_t color, uint16_t bgCol, int clip_h = 240) {
|
||||||
|
int curX = x;
|
||||||
|
uint8_t colorIdx = 0;
|
||||||
|
for (int i = 0; str[i] != '\0'; i++) {
|
||||||
|
char c = str[i];
|
||||||
|
int gIdx = -1;
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
gIdx = c - 'A';
|
||||||
|
} else if (c >= 'a' && c <= 'z') {
|
||||||
|
gIdx = c - 'a';
|
||||||
|
} else if (c == '/') {
|
||||||
|
gIdx = 26;
|
||||||
|
} else if (c == ' ') {
|
||||||
|
gIdx = 27;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gIdx >= 0) {
|
||||||
|
CoordsGlyphAA g;
|
||||||
|
memcpy_P(&g, &s_navTitleGlyphs[gIdx], sizeof(CoordsGlyphAA));
|
||||||
|
uint16_t cCol = isYapaTheme() ? getYapaColor(colorIdx++) : color;
|
||||||
|
drawCoordsAAChar(dst, curX, y, g, s_navTitleAlpha, cCol, bgCol, clip_h);
|
||||||
|
curX += g.xAdv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Draw 100% anti-aliased Subwords (LATITUD, LONGITUD, HDOP, MSNM, DIAGS)
|
||||||
|
template <typename T>
|
||||||
|
inline void drawGpsNavSubword(T &dst, const char *str, int x, int y, uint16_t color, uint16_t bgCol, int clip_h = 240) {
|
||||||
|
int curX = x;
|
||||||
|
uint8_t colorIdx = 0;
|
||||||
|
for (int i = 0; str[i] != '\0'; i++) {
|
||||||
|
char c = str[i];
|
||||||
|
int gIdx = -1;
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
gIdx = c - 'A'; // 0..25
|
||||||
|
} else if (c >= 'a' && c <= 'z') {
|
||||||
|
gIdx = c - 'a'; // 0..25
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
gIdx = 26 + (c - '0'); // 26..35
|
||||||
|
} else if (c == ':') {
|
||||||
|
gIdx = 36;
|
||||||
|
} else if (c == '.') {
|
||||||
|
gIdx = 37;
|
||||||
|
} else if (c == '-') {
|
||||||
|
gIdx = 38;
|
||||||
|
} else if ((uint8_t)c == 0xC2 && (uint8_t)str[i + 1] == 0xB0) {
|
||||||
|
gIdx = 39;
|
||||||
|
i++;
|
||||||
|
} else if ((uint8_t)c == 0xB0 || c == '`') {
|
||||||
|
gIdx = 39;
|
||||||
|
} else if (c == '/') {
|
||||||
|
gIdx = 40;
|
||||||
|
} else if (c == ' ') {
|
||||||
|
gIdx = 41;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gIdx >= 0) {
|
||||||
|
CoordsGlyphAA g;
|
||||||
|
memcpy_P(&g, &s_navSubGlyphs[gIdx], sizeof(CoordsGlyphAA));
|
||||||
|
uint16_t cCol = isYapaTheme() ? getYapaColor(colorIdx++) : color;
|
||||||
|
drawCoordsAAChar(dst, curX, y, g, s_navSubAlpha, cCol, bgCol, clip_h);
|
||||||
|
curX += g.xAdv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Draw 100% anti-aliased Coordinate Value (e.g. "-34.60371°" or "--.-----°")
|
||||||
|
template <typename T>
|
||||||
|
inline void drawCoordsAAValue(T &dst, const char *str, int x, int y, uint16_t color, uint16_t bgCol, int clip_h = 240) {
|
||||||
|
int curX = x;
|
||||||
|
uint8_t colorIdx = 0;
|
||||||
|
for (int i = 0; str[i] != '\0'; i++) {
|
||||||
|
char c = str[i];
|
||||||
|
int gIdx = -1;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
gIdx = c - '0';
|
||||||
|
} else if (c == '.') {
|
||||||
|
gIdx = 10;
|
||||||
|
} else if (c == '-') {
|
||||||
|
gIdx = 11;
|
||||||
|
} else if ((uint8_t)c == 0xC2 && (uint8_t)str[i + 1] == 0xB0) {
|
||||||
|
gIdx = 12;
|
||||||
|
i++;
|
||||||
|
} else if ((uint8_t)c == 0xB0 || c == '`') {
|
||||||
|
gIdx = 12;
|
||||||
|
} else if (c == ' ') {
|
||||||
|
gIdx = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gIdx >= 0) {
|
||||||
|
CoordsGlyphAA g;
|
||||||
|
memcpy_P(&g, &s_coordsValueGlyphs[gIdx], sizeof(CoordsGlyphAA));
|
||||||
|
uint16_t cCol = isYapaTheme() ? getYapaColor(colorIdx++) : color;
|
||||||
|
drawCoordsAAChar(dst, curX, y, g, s_coordsValueAlpha, cCol, bgCol, clip_h);
|
||||||
|
curX += g.xAdv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward-compatible alias for subword labels
|
||||||
|
template <typename T>
|
||||||
|
inline void drawCoordsAALabel(T &dst, const char *str, int x, int y, uint16_t color, uint16_t bgCol, int clip_h = 240) {
|
||||||
|
drawGpsNavSubword(dst, str, x, y, color, bgCol, clip_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -33,6 +33,10 @@ static uint16_t oldClockYear = 0;
|
||||||
static TFT_eSprite sprDayTitle(&tft);
|
static TFT_eSprite sprDayTitle(&tft);
|
||||||
static uint8_t sprDayWday = 255;
|
static uint8_t sprDayWday = 255;
|
||||||
|
|
||||||
|
inline void invalidateGpsClockTitles() {
|
||||||
|
sprDayWday = 255;
|
||||||
|
}
|
||||||
|
|
||||||
inline void updateDayTitleSprite(uint8_t wday) {
|
inline void updateDayTitleSprite(uint8_t wday) {
|
||||||
if (sprDayWday == wday && sprDayTitle.created()) return;
|
if (sprDayWday == wday && sprDayTitle.created()) return;
|
||||||
if (!sprDayTitle.created()) {
|
if (!sprDayTitle.created()) {
|
||||||
|
|
@ -43,8 +47,21 @@ inline void updateDayTitleSprite(uint8_t wday) {
|
||||||
sprDayTitle.loadFont(Latin_Sans_Bold_26);
|
sprDayTitle.loadFont(Latin_Sans_Bold_26);
|
||||||
sprDayTitle.setTextPadding(0);
|
sprDayTitle.setTextPadding(0);
|
||||||
sprDayTitle.fillSprite(cardBg);
|
sprDayTitle.fillSprite(cardBg);
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
int curX = 0;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
String dName = SPANISH_DAYS[wday];
|
||||||
|
for (size_t i = 0; i < dName.length(); i++) {
|
||||||
|
buf[0] = dName[i];
|
||||||
|
if (buf[0] == ' ') { curX += sprDayTitle.textWidth(buf); continue; }
|
||||||
|
sprDayTitle.setTextColor(getYapaColor(i), cardBg);
|
||||||
|
sprDayTitle.drawString(buf, curX, 0);
|
||||||
|
curX += sprDayTitle.textWidth(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
sprDayTitle.setTextColor(TFT_WHITE, cardBg);
|
sprDayTitle.setTextColor(TFT_WHITE, cardBg);
|
||||||
sprDayTitle.drawString(SPANISH_DAYS[wday], 0, 0, 1);
|
sprDayTitle.drawString(SPANISH_DAYS[wday], 0, 0, 1);
|
||||||
|
}
|
||||||
sprDayTitle.unloadFont();
|
sprDayTitle.unloadFont();
|
||||||
if (isRainbowTheme()) {
|
if (isRainbowTheme()) {
|
||||||
applyRainbowToSprite(sprDayTitle, 4 + 116, 125 + 22, cardBg);
|
applyRainbowToSprite(sprDayTitle, 4 + 116, 125 + 22, cardBg);
|
||||||
|
|
@ -67,8 +84,20 @@ inline void updateYearTitleSprite(uint16_t year, uint16_t priCol) {
|
||||||
sprYearTitle.loadFont(Latin_Sans_Bold_26);
|
sprYearTitle.loadFont(Latin_Sans_Bold_26);
|
||||||
sprYearTitle.setTextPadding(0);
|
sprYearTitle.setTextPadding(0);
|
||||||
sprYearTitle.fillSprite(cardBg);
|
sprYearTitle.fillSprite(cardBg);
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
int curX = 0;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
String yStr = String(year);
|
||||||
|
for (size_t i = 0; i < yStr.length(); i++) {
|
||||||
|
buf[0] = yStr[i];
|
||||||
|
sprYearTitle.setTextColor(getYapaColor(i + 2), cardBg);
|
||||||
|
sprYearTitle.drawString(buf, curX, 0);
|
||||||
|
curX += sprYearTitle.textWidth(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
sprYearTitle.setTextColor(priCol, cardBg);
|
sprYearTitle.setTextColor(priCol, cardBg);
|
||||||
sprYearTitle.drawString(String(year).c_str(), 0, 0, 1);
|
sprYearTitle.drawString(String(year).c_str(), 0, 0, 1);
|
||||||
|
}
|
||||||
sprYearTitle.unloadFont();
|
sprYearTitle.unloadFont();
|
||||||
if (isRainbowTheme()) {
|
if (isRainbowTheme()) {
|
||||||
applyRainbowToSprite(sprYearTitle, 4 + 116, 125 + 64, cardBg);
|
applyRainbowToSprite(sprYearTitle, 4 + 116, 125 + 64, cardBg);
|
||||||
|
|
@ -112,22 +141,62 @@ inline void drawDateCardContent(int cardX, int cardY, int cardW, int cardH,
|
||||||
tft.drawRoundRect(bx, by, bw, bh, 6, cardBorder);
|
tft.drawRoundRect(bx, by, bw, bh, 6, cardBorder);
|
||||||
|
|
||||||
// Badge top header (Month abbreviated in Accent Color)
|
// Badge top header (Month abbreviated in Accent Color)
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
tft.fillRoundRect(bx, by, bw, 24, 6, 0x3A53);
|
||||||
|
tft.fillRect(bx, by + 18, bw, 6, 0x3A53);
|
||||||
|
int totalW = tft.textWidth(mShort.c_str(), 2);
|
||||||
|
int startX = bx + (bw - totalW) / 2;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
for (size_t i = 0; i < mShort.length(); i++) {
|
||||||
|
buf[0] = mShort[i];
|
||||||
|
tft.setTextColor(getYapaColor(i), 0x3A53);
|
||||||
|
tft.drawString(buf, startX, by + 4, 2);
|
||||||
|
startX += tft.textWidth(buf, 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
tft.fillRoundRect(bx, by, bw, 24, 6, accCol);
|
tft.fillRoundRect(bx, by, bw, 24, 6, accCol);
|
||||||
tft.fillRect(bx, by + 18, bw, 6, accCol); // flatten lower header corners
|
tft.fillRect(bx, by + 18, bw, 6, accCol); // flatten lower header corners
|
||||||
tft.setTextColor(TFT_BLACK, accCol);
|
tft.setTextColor(TFT_BLACK, accCol);
|
||||||
tft.drawCentreString(mShort.c_str(), bx + (bw / 2), by + 4, 2);
|
tft.drawCentreString(mShort.c_str(), bx + (bw / 2), by + 4, 2);
|
||||||
|
}
|
||||||
|
|
||||||
// Badge body: Big Day Number in DSEG7 34pt
|
// Badge body: Big Day Number in DSEG7 34pt
|
||||||
tft.loadFont(DSEG7_Modern_BoldItalic_34);
|
tft.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
tft.setTextColor(TFT_WHITE, 0x18C3);
|
|
||||||
tft.setTextPadding(0);
|
tft.setTextPadding(0);
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
int totalW = tft.textWidth(dayStr.c_str());
|
||||||
|
int startX = bx + (bw - totalW) / 2;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
for (size_t i = 0; i < dayStr.length(); i++) {
|
||||||
|
buf[0] = dayStr[i];
|
||||||
|
tft.setTextColor(getYapaColor(i), 0x18C3);
|
||||||
|
tft.drawString(buf, startX, by + 34);
|
||||||
|
startX += tft.textWidth(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tft.setTextColor(TFT_WHITE, 0x18C3);
|
||||||
tft.drawCentreString(dayStr.c_str(), bx + (bw / 2), by + 34, 1);
|
tft.drawCentreString(dayStr.c_str(), bx + (bw / 2), by + 34, 1);
|
||||||
|
}
|
||||||
tft.unloadFont();
|
tft.unloadFont();
|
||||||
|
|
||||||
// --- DATE DETAILS (Right side) ---
|
// --- DATE DETAILS (Right side) ---
|
||||||
int tx = cardX + 116;
|
int tx = cardX + 116;
|
||||||
|
|
||||||
// Day of week in Latin Sans Bold 26 (Smooth antialiased, White, uppercase matching Page 1)
|
// Day of week in Latin Sans Bold 26 (Smooth antialiased, White, uppercase matching Page 1)
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
tft.loadFont(Latin_Sans_Bold_26);
|
||||||
|
int curX = tx;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
String dName = SPANISH_DAYS[wday];
|
||||||
|
for (size_t i = 0; i < dName.length(); i++) {
|
||||||
|
buf[0] = dName[i];
|
||||||
|
if (buf[0] == ' ') { curX += tft.textWidth(buf); continue; }
|
||||||
|
tft.setTextColor(getYapaColor(i), cardBg);
|
||||||
|
tft.drawString(buf, curX, cardY + 22);
|
||||||
|
curX += tft.textWidth(buf);
|
||||||
|
}
|
||||||
|
tft.unloadFont();
|
||||||
|
} else {
|
||||||
updateDayTitleSprite(wday);
|
updateDayTitleSprite(wday);
|
||||||
if (sprDayTitle.created()) {
|
if (sprDayTitle.created()) {
|
||||||
sprDayTitle.pushSprite(tx, cardY + 22);
|
sprDayTitle.pushSprite(tx, cardY + 22);
|
||||||
|
|
@ -138,12 +207,26 @@ inline void drawDateCardContent(int cardX, int cardY, int cardW, int cardH,
|
||||||
tft.drawString(SPANISH_DAYS[wday], tx, cardY + 22, 1);
|
tft.drawString(SPANISH_DAYS[wday], tx, cardY + 22, 1);
|
||||||
tft.unloadFont();
|
tft.unloadFont();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Elegant two-tone horizontal dividing line
|
// Elegant two-tone horizontal dividing line
|
||||||
tft.drawFastHLine(tx, cardY + 54, 180, cardBorder);
|
tft.drawFastHLine(tx, cardY + 54, 180, cardBorder);
|
||||||
tft.drawFastHLine(tx, cardY + 54, 50, accCol);
|
tft.drawFastHLine(tx, cardY + 54, 50, isYapaTheme() ? getYapaColor(0) : accCol);
|
||||||
|
|
||||||
// Year in Latin Sans Bold 26 (Smooth antialiased, Accent color)
|
// Year in Latin Sans Bold 26 (Smooth antialiased, Accent color)
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
tft.loadFont(Latin_Sans_Bold_26);
|
||||||
|
int curX = tx;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
String yStr = String(gpsYear);
|
||||||
|
for (size_t i = 0; i < yStr.length(); i++) {
|
||||||
|
buf[0] = yStr[i];
|
||||||
|
tft.setTextColor(getYapaColor(i + 2), cardBg);
|
||||||
|
tft.drawString(buf, curX, cardY + 64);
|
||||||
|
curX += tft.textWidth(buf);
|
||||||
|
}
|
||||||
|
tft.unloadFont();
|
||||||
|
} else {
|
||||||
updateYearTitleSprite(gpsYear, yearCol);
|
updateYearTitleSprite(gpsYear, yearCol);
|
||||||
if (sprYearTitle.created()) {
|
if (sprYearTitle.created()) {
|
||||||
sprYearTitle.pushSprite(tx, cardY + 64);
|
sprYearTitle.pushSprite(tx, cardY + 64);
|
||||||
|
|
@ -155,6 +238,7 @@ inline void drawDateCardContent(int cardX, int cardY, int cardW, int cardH,
|
||||||
tft.unloadFont();
|
tft.unloadFont();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Authentic DSEG7 antialiased dot alpha matrix (from
|
// Authentic DSEG7 antialiased dot alpha matrix (from
|
||||||
// DSEG7_Modern_BoldItalic_80)
|
// DSEG7_Modern_BoldItalic_80)
|
||||||
|
|
@ -264,12 +348,12 @@ inline void drawGpsClockScreen(int x_offset = 0) {
|
||||||
uint16_t cardBorder = 0x2945; // Subtle edge border
|
uint16_t cardBorder = 0x2945; // Subtle edge border
|
||||||
bool synced = isGpsSynced();
|
bool synced = isGpsSynced();
|
||||||
|
|
||||||
// 1. TOP BAR (y = 0 to 18)
|
// Center: 5 Pagination Indicator Dots [○ ○ ● ○ ○] (Page 2 of 5 active)
|
||||||
// Center: 4 Pagination Indicator Dots [○ ○ ● ○] (Page 3 active)
|
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
tft.fillCircle(146 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||||
tft.fillCircle(153 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
tft.fillCircle(160 + x_offset, 2, 2, priCol); // Page 2 active
|
||||||
tft.fillCircle(167 + x_offset, 2, 2, priCol); // Page 3 active
|
tft.fillCircle(174 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
||||||
tft.fillCircle(181 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
tft.fillCircle(188 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
||||||
|
|
||||||
// 2. MAIN CLOCK CARD (y = 19 to 121, height = 102, width = 312, x = 4)
|
// 2. MAIN CLOCK CARD (y = 19 to 121, height = 102, width = 312, x = 4)
|
||||||
int clkX = 4 + x_offset;
|
int clkX = 4 + x_offset;
|
||||||
|
|
@ -289,11 +373,15 @@ inline void drawGpsClockScreen(int x_offset = 0) {
|
||||||
uint8_t m10 = (gpsMinute / 10) % 10;
|
uint8_t m10 = (gpsMinute / 10) % 10;
|
||||||
uint8_t m1 = gpsMinute % 10;
|
uint8_t m1 = gpsMinute % 10;
|
||||||
bool rbClk = isRainbowTheme();
|
bool rbClk = isRainbowTheme();
|
||||||
|
uint16_t c_h10 = isYapaTheme() ? getYapaColor(0) : clkAccCol;
|
||||||
|
uint16_t c_h1 = isYapaTheme() ? getYapaColor(1) : clkAccCol;
|
||||||
|
uint16_t c_m10 = isYapaTheme() ? getYapaColor(2) : clkAccCol;
|
||||||
|
uint16_t c_m1 = isYapaTheme() ? getYapaColor(3) : clkAccCol;
|
||||||
|
|
||||||
drawDseg7Digit80(tft, clkX + 12, clkY + 11, h10, clkAccCol, cardBg, 240, rbClk);
|
drawDseg7Digit80(tft, clkX + 12, clkY + 11, h10, c_h10, cardBg, 240, rbClk);
|
||||||
drawDseg7Digit80(tft, clkX + 77, clkY + 11, h1, clkAccCol, cardBg, 240, rbClk);
|
drawDseg7Digit80(tft, clkX + 77, clkY + 11, h1, c_h1, cardBg, 240, rbClk);
|
||||||
drawDseg7Digit80(tft, clkX + 170, clkY + 11, m10, clkAccCol, cardBg, 240, rbClk);
|
drawDseg7Digit80(tft, clkX + 170, clkY + 11, m10, c_m10, cardBg, 240, rbClk);
|
||||||
drawDseg7Digit80(tft, clkX + 235, clkY + 11, m1, clkAccCol, cardBg, 240, rbClk);
|
drawDseg7Digit80(tft, clkX + 235, clkY + 11, m1, c_m1, cardBg, 240, rbClk);
|
||||||
|
|
||||||
// Blinking Colon Dots between HH and MM (italic 7-segment style with
|
// Blinking Colon Dots between HH and MM (italic 7-segment style with
|
||||||
// anti-aliasing)
|
// anti-aliasing)
|
||||||
|
|
@ -339,8 +427,10 @@ inline void updateGpsClockScreen(bool forceRedraw = false) {
|
||||||
tft.fillRect(clkX + 166, clkY + 10, 142, 82, cardBg);
|
tft.fillRect(clkX + 166, clkY + 10, 142, 82, cardBg);
|
||||||
uint8_t m10 = (gpsMinute / 10) % 10;
|
uint8_t m10 = (gpsMinute / 10) % 10;
|
||||||
uint8_t m1 = gpsMinute % 10;
|
uint8_t m1 = gpsMinute % 10;
|
||||||
drawDseg7Digit80(tft, clkX + 170, clkY + 11, m10, clkAccCol, cardBg, 240, isRainbowTheme());
|
uint16_t c_m10 = isYapaTheme() ? getYapaColor(2) : clkAccCol;
|
||||||
drawDseg7Digit80(tft, clkX + 235, clkY + 11, m1, clkAccCol, cardBg, 240, isRainbowTheme());
|
uint16_t c_m1 = isYapaTheme() ? getYapaColor(3) : clkAccCol;
|
||||||
|
drawDseg7Digit80(tft, clkX + 170, clkY + 11, m10, c_m10, cardBg, 240, isRainbowTheme());
|
||||||
|
drawDseg7Digit80(tft, clkX + 235, clkY + 11, m1, c_m1, cardBg, 240, isRainbowTheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Hours change: update HH digits
|
// 3. Hours change: update HH digits
|
||||||
|
|
@ -349,8 +439,10 @@ inline void updateGpsClockScreen(bool forceRedraw = false) {
|
||||||
tft.fillRect(clkX + 12, clkY + 10, 136, 82, cardBg);
|
tft.fillRect(clkX + 12, clkY + 10, 136, 82, cardBg);
|
||||||
uint8_t h10 = (gpsHour / 10) % 10;
|
uint8_t h10 = (gpsHour / 10) % 10;
|
||||||
uint8_t h1 = gpsHour % 10;
|
uint8_t h1 = gpsHour % 10;
|
||||||
drawDseg7Digit80(tft, clkX + 12, clkY + 11, h10, clkAccCol, cardBg, 240, isRainbowTheme());
|
uint16_t c_h10 = isYapaTheme() ? getYapaColor(0) : clkAccCol;
|
||||||
drawDseg7Digit80(tft, clkX + 77, clkY + 11, h1, clkAccCol, cardBg, 240, isRainbowTheme());
|
uint16_t c_h1 = isYapaTheme() ? getYapaColor(1) : clkAccCol;
|
||||||
|
drawDseg7Digit80(tft, clkX + 12, clkY + 11, h10, c_h10, cardBg, 240, isRainbowTheme());
|
||||||
|
drawDseg7Digit80(tft, clkX + 77, clkY + 11, h1, c_h1, cardBg, 240, isRainbowTheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Date changed (midnight rollover): redraw full date card
|
// 4. Date changed (midnight rollover): redraw full date card
|
||||||
|
|
@ -403,10 +495,15 @@ inline void renderPage2ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
||||||
uint8_t m10 = (gpsMinute / 10) % 10;
|
uint8_t m10 = (gpsMinute / 10) % 10;
|
||||||
uint8_t m1 = gpsMinute % 10;
|
uint8_t m1 = gpsMinute % 10;
|
||||||
|
|
||||||
drawDseg7Digit80(s, clkX + 12, digitY, h10, clkAccCol, cardBg, slice_h, isRainbowTheme());
|
uint16_t c_h10 = isYapaTheme() ? getYapaColor(0) : clkAccCol;
|
||||||
drawDseg7Digit80(s, clkX + 77, digitY, h1, clkAccCol, cardBg, slice_h, isRainbowTheme());
|
uint16_t c_h1 = isYapaTheme() ? getYapaColor(1) : clkAccCol;
|
||||||
drawDseg7Digit80(s, clkX + 170, digitY, m10, clkAccCol, cardBg, slice_h, isRainbowTheme());
|
uint16_t c_m10 = isYapaTheme() ? getYapaColor(2) : clkAccCol;
|
||||||
drawDseg7Digit80(s, clkX + 235, digitY, m1, clkAccCol, cardBg, slice_h, isRainbowTheme());
|
uint16_t c_m1 = isYapaTheme() ? getYapaColor(3) : clkAccCol;
|
||||||
|
|
||||||
|
drawDseg7Digit80(s, clkX + 12, digitY, h10, c_h10, cardBg, slice_h, isRainbowTheme());
|
||||||
|
drawDseg7Digit80(s, clkX + 77, digitY, h1, c_h1, cardBg, slice_h, isRainbowTheme());
|
||||||
|
drawDseg7Digit80(s, clkX + 170, digitY, m10, c_m10, cardBg, slice_h, isRainbowTheme());
|
||||||
|
drawDseg7Digit80(s, clkX + 235, digitY, m1, c_m1, cardBg, slice_h, isRainbowTheme());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,7 +530,35 @@ inline void renderPage2ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
||||||
s.fillRoundRect(bx, by, bw, bh, 6, 0x18C3);
|
s.fillRoundRect(bx, by, bw, bh, 6, 0x18C3);
|
||||||
s.drawRoundRect(bx, by, bw, bh, 6, cardBorder);
|
s.drawRoundRect(bx, by, bw, bh, 6, cardBorder);
|
||||||
|
|
||||||
// Header strip
|
if (isYapaTheme()) {
|
||||||
|
s.fillRoundRect(bx, by, bw, 24, 6, 0x3A53);
|
||||||
|
s.fillRect(bx, by + 18, bw, 6, 0x3A53);
|
||||||
|
uint8_t mIdx = (gpsMonth >= 1 && gpsMonth <= 12) ? (gpsMonth - 1) : 0;
|
||||||
|
String mShort = SPANISH_MONTHS_SHORT[mIdx];
|
||||||
|
int totalW = s.textWidth(mShort.c_str(), 2);
|
||||||
|
int startX = bx + (bw - totalW) / 2;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
for (size_t i = 0; i < mShort.length(); i++) {
|
||||||
|
buf[0] = mShort[i];
|
||||||
|
s.setTextColor(getYapaColor(i), 0x3A53);
|
||||||
|
s.drawString(buf, startX, by + 4, 2);
|
||||||
|
startX += s.textWidth(buf, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Badge day number in Yapa
|
||||||
|
String dayStr = (gpsDay < 10) ? "0" + String(gpsDay) : String(gpsDay);
|
||||||
|
s.loadFont(DSEG7_Modern_BoldItalic_34);
|
||||||
|
s.setTextPadding(0);
|
||||||
|
int dayW = s.textWidth(dayStr.c_str());
|
||||||
|
int dStartX = bx + (bw - dayW) / 2;
|
||||||
|
for (size_t i = 0; i < dayStr.length(); i++) {
|
||||||
|
buf[0] = dayStr[i];
|
||||||
|
s.setTextColor(getYapaColor(i), 0x18C3);
|
||||||
|
s.drawString(buf, dStartX, by + 34);
|
||||||
|
dStartX += s.textWidth(buf);
|
||||||
|
}
|
||||||
|
s.unloadFont();
|
||||||
|
} else {
|
||||||
s.fillRoundRect(bx, by, bw, 24, 6, dateAccCol);
|
s.fillRoundRect(bx, by, bw, 24, 6, dateAccCol);
|
||||||
s.fillRect(bx, by + 18, bw, 6, dateAccCol);
|
s.fillRect(bx, by + 18, bw, 6, dateAccCol);
|
||||||
uint8_t mIdx = (gpsMonth >= 1 && gpsMonth <= 12) ? (gpsMonth - 1) : 0;
|
uint8_t mIdx = (gpsMonth >= 1 && gpsMonth <= 12) ? (gpsMonth - 1) : 0;
|
||||||
|
|
@ -448,6 +573,7 @@ inline void renderPage2ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
||||||
s.drawCentreString(dayStr.c_str(), bx + (bw / 2), by + 34, 1);
|
s.drawCentreString(dayStr.c_str(), bx + (bw / 2), by + 34, 1);
|
||||||
s.fontLoaded = false;
|
s.fontLoaded = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int tx = dateX + 116;
|
int tx = dateX + 116;
|
||||||
uint8_t wday = gpsDayOfWeek % 7;
|
uint8_t wday = gpsDayOfWeek % 7;
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,14 @@
|
||||||
#include "gps_module.h"
|
#include "gps_module.h"
|
||||||
#include "DSEG7_Modern_BoldItalic_34.h"
|
#include "DSEG7_Modern_BoldItalic_34.h"
|
||||||
#include "rainbow_text.h"
|
#include "rainbow_text.h"
|
||||||
|
#include "coords_font.h"
|
||||||
|
|
||||||
extern TFT_eSPI tft;
|
extern TFT_eSPI tft;
|
||||||
extern uint16_t getThemePrimaryColor();
|
extern uint16_t getThemePrimaryColor();
|
||||||
extern uint16_t getThemeAccentColor();
|
extern uint16_t getThemeAccentColor();
|
||||||
extern uint16_t getThemeBgColor();
|
extern uint16_t getThemeBgColor();
|
||||||
extern bool isRainbowTheme();
|
extern bool isRainbowTheme();
|
||||||
|
extern bool isYapaTheme();
|
||||||
extern int8_t currentScreenPage;
|
extern int8_t currentScreenPage;
|
||||||
extern int8_t fullScreenCell;
|
extern int8_t fullScreenCell;
|
||||||
|
|
||||||
|
|
@ -93,20 +95,20 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
|
|
||||||
uint16_t priCol = getThemePrimaryColor();
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
uint16_t accCol = getThemeAccentColor();
|
uint16_t accCol = getThemeAccentColor();
|
||||||
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : priCol;
|
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : accCol;
|
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : priCol;
|
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : accCol;
|
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
uint16_t cardBg = 0x10A2; // Dark graphite navy
|
uint16_t cardBg = 0x10A2; // Dark graphite navy
|
||||||
uint16_t cardBorder = 0x2945; // Subtle edge border
|
uint16_t cardBorder = 0x2945; // Subtle edge border
|
||||||
bool synced = isGpsSynced();
|
bool synced = isGpsSynced();
|
||||||
|
|
||||||
// 1. TOP BAR (y = 0 to 18)
|
// Center: 5 Pagination Indicator Dots [○ ○ ○ ● ○] (Page 3 of 5 active)
|
||||||
// Center: 4 Pagination Indicator Dots [○ ○ ○ ●] (Page 4 active)
|
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
tft.fillCircle(146 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||||
tft.fillCircle(153 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
tft.fillCircle(160 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
||||||
tft.fillCircle(167 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
tft.fillCircle(174 + x_offset, 2, 2, priCol); // Page 3 active
|
||||||
tft.fillCircle(181 + x_offset, 2, 2, priCol); // Page 4 active
|
tft.fillCircle(188 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
||||||
|
|
||||||
// 2. CARD 0 (Top Left): ALTITUD (x = 4, y = 19, w = 152, h = 102)
|
// 2. CARD 0 (Top Left): ALTITUD (x = 4, y = 19, w = 152, h = 102)
|
||||||
int c0X = 4 + x_offset;
|
int c0X = 4 + x_offset;
|
||||||
|
|
@ -117,10 +119,8 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
tft.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
tft.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
||||||
tft.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
tft.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavTitle(tft, "ALTITUD", c0X + 16, c0Y + 8, 0x8410, cardBg, 240);
|
||||||
tft.drawString("ALTITUD", c0X + 16, c0Y + 8, 2);
|
drawGpsNavSubword(tft, "MSNM", c0X + 96, c0Y + 9, 0x9CD3, cardBg, 240);
|
||||||
tft.setTextColor(0x9CD3, cardBg);
|
|
||||||
tft.drawString("MSNM", c0X + 96, c0Y + 8, 2);
|
|
||||||
|
|
||||||
bool altValid = isGpsAltitudeValid();
|
bool altValid = isGpsAltitudeValid();
|
||||||
String altStr = altValid ? String((int)round(gpsAltitudeM)) : "---";
|
String altStr = altValid ? String((int)round(gpsAltitudeM)) : "---";
|
||||||
|
|
@ -133,8 +133,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
tft.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
tft.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
||||||
tft.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
tft.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavTitle(tft, "RUMBO / BRUJULA", c1X + 16, c1Y + 8, 0x8410, cardBg, 240);
|
||||||
tft.drawString("RUMBO / BRUJULA", c1X + 16, c1Y + 8, 2);
|
|
||||||
|
|
||||||
bool hasCourse = synced && isGpsCourseValid();
|
bool hasCourse = synced && isGpsCourseValid();
|
||||||
String crsStr = hasCourse ? String((int)round(gpsCourseDeg)) : "---";
|
String crsStr = hasCourse ? String((int)round(gpsCourseDeg)) : "---";
|
||||||
|
|
@ -147,8 +146,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
||||||
tft.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(tft, cardDir, c1X + 16, c1Y + 76, TFT_WHITE, cardBg, 240);
|
||||||
tft.drawString(cardDir, c1X + 16, c1Y + 74, 2);
|
|
||||||
|
|
||||||
// 4. CARD 2 (Bottom Left): SATÉLITES GPS EN GRANDE (x = 4, y = 125, w = 152, h = 110)
|
// 4. CARD 2 (Bottom Left): SATÉLITES GPS EN GRANDE (x = 4, y = 125, w = 152, h = 110)
|
||||||
int c2X = 4 + x_offset;
|
int c2X = 4 + x_offset;
|
||||||
|
|
@ -158,8 +156,7 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
tft.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
tft.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
||||||
tft.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
tft.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavTitle(tft, "SATELITES GPS", c2X + 16, c2Y + 8, 0x8410, cardBg, 240);
|
||||||
tft.drawString("SATELITES GPS", c2X + 16, c2Y + 8, 2);
|
|
||||||
|
|
||||||
// Large Satellite Icon (animated body + waves)
|
// Large Satellite Icon (animated body + waves)
|
||||||
uint8_t waveState = getGpsWaveAnimState();
|
uint8_t waveState = getGpsWaveAnimState();
|
||||||
|
|
@ -171,11 +168,9 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
|
|
||||||
// Telemetry details: HDOP precision & live diagnostic status
|
// Telemetry details: HDOP precision & live diagnostic status
|
||||||
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
||||||
tft.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(tft, hdopStr.c_str(), c2X + 16, c2Y + 70, TFT_WHITE, cardBg, 240);
|
||||||
tft.drawString(hdopStr.c_str(), c2X + 16, c2Y + 68, 2);
|
|
||||||
|
|
||||||
tft.setTextColor(synced ? 0x9CD3 : priCol, cardBg);
|
drawGpsNavSubword(tft, getGpsDiagMessage(), c2X + 16, c2Y + 90, synced ? 0x9CD3 : priCol, cardBg, 240);
|
||||||
tft.drawString(getGpsDiagMessage(), c2X + 16, c2Y + 90, 1);
|
|
||||||
|
|
||||||
// 5. CARD 3 (Bottom Right): COORDENADAS GPS (x = 164, y = 125, w = 152, h = 110)
|
// 5. CARD 3 (Bottom Right): COORDENADAS GPS (x = 164, y = 125, w = 152, h = 110)
|
||||||
int c3X = 164 + x_offset;
|
int c3X = 164 + x_offset;
|
||||||
|
|
@ -184,20 +179,15 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
||||||
tft.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
tft.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
||||||
tft.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
tft.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavTitle(tft, "COORDENADAS", c3X + 16, c3Y + 8, 0x8410, cardBg, 240);
|
||||||
tft.drawString("COORDENADAS", c3X + 16, c3Y + 8, 2);
|
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavSubword(tft, "LATITUD", c3X + 16, c3Y + 24, 0x8410, cardBg, 240);
|
||||||
tft.drawString("LAT", c3X + 16, c3Y + 26, 1);
|
|
||||||
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
||||||
tft.setTextColor(c3Col, cardBg);
|
drawCoordsAAValue(tft, latStr.c_str(), c3X + 16, c3Y + 38, c3Col, cardBg, 240);
|
||||||
tft.drawString(latStr.c_str(), c3X + 16, c3Y + 38, 2);
|
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg);
|
drawGpsNavSubword(tft, "LONGITUD", c3X + 16, c3Y + 62, 0x8410, cardBg, 240);
|
||||||
tft.drawString("LON", c3X + 16, c3Y + 64, 1);
|
|
||||||
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
||||||
tft.setTextColor(c3Col, cardBg);
|
drawCoordsAAValue(tft, lonStr.c_str(), c3X + 16, c3Y + 76, c3Col, cardBg, 240);
|
||||||
tft.drawString(lonStr.c_str(), c3X + 16, c3Y + 76, 2);
|
|
||||||
|
|
||||||
// Sync state trackers
|
// Sync state trackers
|
||||||
syncGpsNavTrackers();
|
syncGpsNavTrackers();
|
||||||
|
|
@ -217,10 +207,10 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
|
|
||||||
uint16_t priCol = getThemePrimaryColor();
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
uint16_t accCol = getThemeAccentColor();
|
uint16_t accCol = getThemeAccentColor();
|
||||||
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : priCol;
|
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : accCol;
|
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : priCol;
|
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : accCol;
|
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
uint16_t cardBg = 0x10A2;
|
uint16_t cardBg = 0x10A2;
|
||||||
bool synced = isGpsSynced();
|
bool synced = isGpsSynced();
|
||||||
|
|
||||||
|
|
@ -262,10 +252,8 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
||||||
if (forceRedraw || strcmp(cardDir, lastNavCardDir) != 0) {
|
if (forceRedraw || strcmp(cardDir, lastNavCardDir) != 0) {
|
||||||
lastNavCardDir = cardDir;
|
lastNavCardDir = cardDir;
|
||||||
tft.setTextPadding(128);
|
tft.fillRect(c1X + 16, c1Y + 74, 128, 16, cardBg);
|
||||||
tft.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(tft, cardDir, c1X + 16, c1Y + 76, TFT_WHITE, cardBg, 240);
|
||||||
tft.drawString(cardDir, c1X + 16, c1Y + 74, 2);
|
|
||||||
tft.setTextPadding(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Card 2: Satellites, HDOP and Diagnostic status
|
// 3. Card 2: Satellites, HDOP and Diagnostic status
|
||||||
|
|
@ -288,10 +276,8 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
lastNavCardHdop = gpsHdop;
|
lastNavCardHdop = gpsHdop;
|
||||||
oldNavHdop = gpsHdop;
|
oldNavHdop = gpsHdop;
|
||||||
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
||||||
tft.setTextPadding(130);
|
tft.fillRect(c2X + 16, c2Y + 68, 130, 16, cardBg);
|
||||||
tft.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(tft, hdopStr.c_str(), c2X + 16, c2Y + 70, TFT_WHITE, cardBg, 240);
|
||||||
tft.drawString(hdopStr.c_str(), c2X + 16, c2Y + 68, 2);
|
|
||||||
tft.setTextPadding(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3c. Diagnostic status message ("PRECISION OPTIMA", "SIN SEÑAL GPS", etc.)
|
// 3c. Diagnostic status message ("PRECISION OPTIMA", "SIN SEÑAL GPS", etc.)
|
||||||
|
|
@ -301,10 +287,8 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
strncpy(lastNavCardDiag, curDiag, sizeof(lastNavCardDiag) - 1);
|
strncpy(lastNavCardDiag, curDiag, sizeof(lastNavCardDiag) - 1);
|
||||||
lastNavCardDiag[sizeof(lastNavCardDiag) - 1] = '\0';
|
lastNavCardDiag[sizeof(lastNavCardDiag) - 1] = '\0';
|
||||||
lastNavDiagSynced = synced;
|
lastNavDiagSynced = synced;
|
||||||
tft.setTextPadding(130);
|
tft.fillRect(c2X + 16, c2Y + 88, 130, 16, cardBg);
|
||||||
tft.setTextColor(synced ? 0x9CD3 : c2Col, cardBg);
|
drawGpsNavSubword(tft, curDiag, c2X + 16, c2Y + 90, synced ? 0x9CD3 : c2Col, cardBg, 240);
|
||||||
tft.drawString(curDiag, c2X + 16, c2Y + 90, 1);
|
|
||||||
tft.setTextPadding(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3d. Large Satellite Icon: only redrawn if waveState or sync changes
|
// 3d. Large Satellite Icon: only redrawn if waveState or sync changes
|
||||||
|
|
@ -315,20 +299,20 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
drawLargeSatelliteIcon(c2X + 16, c2Y + 32, c2Col, curWaveState, cardBg);
|
drawLargeSatelliteIcon(c2X + 16, c2Y + 32, c2Col, curWaveState, cardBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Coordinates changed: update Card 3 (setTextPadding avoids fillRect flicker)
|
// 4. Coordinates changed: update Card 3 (clear exact value region and redraw anti-aliased value)
|
||||||
if (forceRedraw || abs(gpsLatitude - oldNavLat) >= 0.00005 || abs(gpsLongitude - oldNavLon) >= 0.00005) {
|
if (forceRedraw || abs(gpsLatitude - oldNavLat) >= 0.00005 || abs(gpsLongitude - oldNavLon) >= 0.00005) {
|
||||||
oldNavLat = gpsLatitude;
|
oldNavLat = gpsLatitude;
|
||||||
oldNavLon = gpsLongitude;
|
oldNavLon = gpsLongitude;
|
||||||
int c3X = 164;
|
int c3X = 164;
|
||||||
int c3Y = 125;
|
int c3Y = 125;
|
||||||
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
||||||
tft.setTextPadding(130);
|
|
||||||
tft.setTextColor(c3Col, cardBg);
|
|
||||||
tft.drawString(latStr.c_str(), c3X + 16, c3Y + 38, 2);
|
|
||||||
|
|
||||||
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
||||||
tft.drawString(lonStr.c_str(), c3X + 16, c3Y + 76, 2);
|
|
||||||
tft.setTextPadding(0);
|
tft.fillRect(c3X + 16, c3Y + 38, 130, 20, cardBg);
|
||||||
|
drawCoordsAAValue(tft, latStr.c_str(), c3X + 16, c3Y + 38, c3Col, cardBg, 240);
|
||||||
|
|
||||||
|
tft.fillRect(c3X + 16, c3Y + 76, 130, 20, cardBg);
|
||||||
|
drawCoordsAAValue(tft, lonStr.c_str(), c3X + 16, c3Y + 76, c3Col, cardBg, 240);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,10 +320,10 @@ inline void updateGpsNavScreen(bool forceRedraw = false) {
|
||||||
inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int slice_h) {
|
inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int slice_h) {
|
||||||
uint16_t priCol = getThemePrimaryColor();
|
uint16_t priCol = getThemePrimaryColor();
|
||||||
uint16_t accCol = getThemeAccentColor();
|
uint16_t accCol = getThemeAccentColor();
|
||||||
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : priCol;
|
uint16_t c0Col = isRainbowTheme() ? (uint16_t)0x07FF : (isYapaTheme() ? getYapaColor(0) : priCol);
|
||||||
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : accCol;
|
uint16_t c1Col = isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : accCol);
|
||||||
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : priCol;
|
uint16_t c2Col = isRainbowTheme() ? (uint16_t)0xFFE0 : (isYapaTheme() ? getYapaColor(2) : priCol);
|
||||||
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : accCol;
|
uint16_t c3Col = isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(3) : accCol);
|
||||||
uint16_t cardBg = 0x10A2;
|
uint16_t cardBg = 0x10A2;
|
||||||
uint16_t cardBorder = 0x2945;
|
uint16_t cardBorder = 0x2945;
|
||||||
bool synced = isGpsSynced();
|
bool synced = isGpsSynced();
|
||||||
|
|
@ -354,12 +338,8 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
s.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
s.drawRoundRect(c0X, c0Y, cW, cH1, 6, cardBorder);
|
||||||
s.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
s.fillRoundRect(c0X + 6, c0Y + 8, 4, cH1 - 16, 2, c0Col);
|
||||||
|
|
||||||
if (c0Y + 24 > 0 && c0Y + 8 < slice_h) {
|
drawGpsNavTitle(s, "ALTITUD", c0X + 16, c0Y + 8, 0x8410, cardBg, slice_h);
|
||||||
s.setTextColor(0x8410, cardBg);
|
drawGpsNavSubword(s, "MSNM", c0X + 96, c0Y + 9, 0x9CD3, cardBg, slice_h);
|
||||||
s.drawString("ALTITUD", c0X + 16, c0Y + 8, 2);
|
|
||||||
s.setTextColor(0x9CD3, cardBg);
|
|
||||||
s.drawString("MSNM", c0X + 96, c0Y + 8, 2);
|
|
||||||
}
|
|
||||||
bool altValid = isGpsAltitudeValid();
|
bool altValid = isGpsAltitudeValid();
|
||||||
String altStr = altValid ? String((int)round(gpsAltitudeM)) : "---";
|
String altStr = altValid ? String((int)round(gpsAltitudeM)) : "---";
|
||||||
int valY = c0Y + 28;
|
int valY = c0Y + 28;
|
||||||
|
|
@ -376,10 +356,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
s.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
s.drawRoundRect(c1X, c1Y, cW, cH1, 6, cardBorder);
|
||||||
s.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
s.fillRoundRect(c1X + 6, c1Y + 8, 4, cH1 - 16, 2, c1Col);
|
||||||
|
|
||||||
if (c1Y + 24 > 0 && c1Y + 8 < slice_h) {
|
drawGpsNavTitle(s, "RUMBO / BRUJULA", c1X + 16, c1Y + 8, 0x8410, cardBg, slice_h);
|
||||||
s.setTextColor(0x8410, cardBg);
|
|
||||||
s.drawString("RUMBO / BRUJULA", c1X + 16, c1Y + 8, 2);
|
|
||||||
}
|
|
||||||
bool hasCourse = synced && isGpsCourseValid();
|
bool hasCourse = synced && isGpsCourseValid();
|
||||||
String crsStr = hasCourse ? String((int)round(gpsCourseDeg)) : "---";
|
String crsStr = hasCourse ? String((int)round(gpsCourseDeg)) : "---";
|
||||||
int valY = c1Y + 28;
|
int valY = c1Y + 28;
|
||||||
|
|
@ -393,12 +370,8 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int dirY = c1Y + 74;
|
|
||||||
if (dirY + 16 > 0 && dirY < slice_h) {
|
|
||||||
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
const char* cardDir = hasCourse ? getCompassDirectionFull(gpsCourseDeg) : "---";
|
||||||
s.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(s, cardDir, c1X + 16, c1Y + 76, TFT_WHITE, cardBg, slice_h);
|
||||||
s.drawString(cardDir, c1X + 16, dirY, 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. CARD 2 (Bottom Left): SATÉLITES GPS (y = 125 to 235)
|
// 4. CARD 2 (Bottom Left): SATÉLITES GPS (y = 125 to 235)
|
||||||
|
|
@ -410,10 +383,7 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
s.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
s.drawRoundRect(c2X, c2Y, cW, cH2, 6, cardBorder);
|
||||||
s.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
s.fillRoundRect(c2X + 6, c2Y + 8, 4, cH2 - 16, 2, c2Col);
|
||||||
|
|
||||||
if (c2Y + 24 > 0 && c2Y + 8 < slice_h) {
|
drawGpsNavTitle(s, "SATELITES GPS", c2X + 16, c2Y + 8, 0x8410, cardBg, slice_h);
|
||||||
s.setTextColor(0x8410, cardBg);
|
|
||||||
s.drawString("SATELITES GPS", c2X + 16, c2Y + 8, 2);
|
|
||||||
}
|
|
||||||
uint8_t waveState = getGpsWaveAnimState();
|
uint8_t waveState = getGpsWaveAnimState();
|
||||||
int icnY = c2Y + 32;
|
int icnY = c2Y + 32;
|
||||||
if (icnY + 28 > 0 && icnY < slice_h) {
|
if (icnY + 28 > 0 && icnY < slice_h) {
|
||||||
|
|
@ -424,17 +394,9 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
String satStr = isGpsUartLocked() ? String(gpsSats) : "---";
|
String satStr = isGpsUartLocked() ? String(gpsSats) : "---";
|
||||||
drawDseg7RightString34(s, satStr.c_str(), c2X + 140, satY, c2Col, cardBg, 0, slice_h, isRainbowTheme());
|
drawDseg7RightString34(s, satStr.c_str(), c2X + 140, satY, c2Col, cardBg, 0, slice_h, isRainbowTheme());
|
||||||
}
|
}
|
||||||
int hdopY = c2Y + 68;
|
|
||||||
if (hdopY < slice_h && hdopY + 16 > 0) {
|
|
||||||
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
String hdopStr = "HDOP: " + (synced ? String(gpsHdop, 1) : "---");
|
||||||
s.setTextColor(TFT_WHITE, cardBg);
|
drawGpsNavSubword(s, hdopStr.c_str(), c2X + 16, c2Y + 70, TFT_WHITE, cardBg, slice_h);
|
||||||
s.drawString(hdopStr.c_str(), c2X + 16, hdopY, 2);
|
drawGpsNavSubword(s, getGpsDiagMessage(), c2X + 16, c2Y + 90, synced ? 0x9CD3 : c2Col, cardBg, slice_h);
|
||||||
}
|
|
||||||
int qualY = c2Y + 90;
|
|
||||||
if (qualY + 10 > 0 && qualY < slice_h) {
|
|
||||||
s.setTextColor(synced ? 0x9CD3 : c2Col, cardBg);
|
|
||||||
s.drawString(getGpsDiagMessage(), c2X + 16, qualY, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. CARD 3 (Bottom Right): COORDENADAS (y = 125 to 235)
|
// 5. CARD 3 (Bottom Right): COORDENADAS (y = 125 to 235)
|
||||||
|
|
@ -445,31 +407,14 @@ inline void renderPage3ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
||||||
s.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
s.drawRoundRect(c3X, c3Y, cW, cH2, 6, cardBorder);
|
||||||
s.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
s.fillRoundRect(c3X + 6, c3Y + 8, 4, cH2 - 16, 2, c3Col);
|
||||||
|
|
||||||
if (c3Y + 24 > 0 && c3Y + 8 < slice_h) {
|
drawGpsNavTitle(s, "COORDENADAS", c3X + 16, c3Y + 8, 0x8410, cardBg, slice_h);
|
||||||
s.setTextColor(0x8410, cardBg);
|
|
||||||
s.drawString("COORDENADAS", c3X + 16, c3Y + 8, 2);
|
drawGpsNavSubword(s, "LATITUD", c3X + 16, c3Y + 24, 0x8410, cardBg, slice_h);
|
||||||
}
|
|
||||||
int latHdrY = c3Y + 26;
|
|
||||||
if (latHdrY < slice_h && latHdrY + 10 > 0) {
|
|
||||||
s.setTextColor(0x8410, cardBg);
|
|
||||||
s.drawString("LAT", c3X + 16, latHdrY, 1);
|
|
||||||
}
|
|
||||||
int latValY = c3Y + 38;
|
|
||||||
if (latValY < slice_h && latValY + 18 > 0) {
|
|
||||||
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
String latStr = gpsLocationValid ? (String(gpsLatitude, 5) + "°") : "--.-----°";
|
||||||
s.setTextColor(c3Col, cardBg);
|
drawCoordsAAValue(s, latStr.c_str(), c3X + 16, c3Y + 38, c3Col, cardBg, slice_h);
|
||||||
s.drawString(latStr.c_str(), c3X + 16, latValY, 2);
|
|
||||||
}
|
drawGpsNavSubword(s, "LONGITUD", c3X + 16, c3Y + 62, 0x8410, cardBg, slice_h);
|
||||||
int lonHdrY = c3Y + 64;
|
|
||||||
if (lonHdrY < slice_h && lonHdrY + 10 > 0) {
|
|
||||||
s.setTextColor(0x8410, cardBg);
|
|
||||||
s.drawString("LON", c3X + 16, lonHdrY, 1);
|
|
||||||
}
|
|
||||||
int lonValY = c3Y + 76;
|
|
||||||
if (lonValY < slice_h && lonValY + 18 > 0) {
|
|
||||||
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
String lonStr = gpsLocationValid ? (String(gpsLongitude, 5) + "°") : "--.-----°";
|
||||||
s.setTextColor(c3Col, cardBg);
|
drawCoordsAAValue(s, lonStr.c_str(), c3X + 16, c3Y + 76, c3Col, cardBg, slice_h);
|
||||||
s.drawString(lonStr.c_str(), c3X + 16, lonValY, 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ extern bool sprTransAllocated;
|
||||||
extern TFT_eSprite sprFadeB;
|
extern TFT_eSprite sprFadeB;
|
||||||
extern bool sprFadeBAllocated;
|
extern bool sprFadeBAllocated;
|
||||||
|
|
||||||
|
extern uint8_t targetBacklight;
|
||||||
|
extern float currentBacklight;
|
||||||
|
|
||||||
const uint16_t screenWidth = tft.height(); // landscape
|
const uint16_t screenWidth = tft.height(); // landscape
|
||||||
const uint16_t screenHeight = tft.width();
|
const uint16_t screenHeight = tft.width();
|
||||||
/*---- METER ------_*
|
/*---- METER ------_*
|
||||||
|
|
@ -239,10 +242,16 @@ void drawFullScreenTitle(const String &label, uint16_t color) {
|
||||||
tft.drawFastHLine(60, y, 195, bgCol);
|
tft.drawFastHLine(60, y, 195, bgCol);
|
||||||
}
|
}
|
||||||
if (color != 0) {
|
if (color != 0) {
|
||||||
|
if (color == TFT_WHITE && isYapaTheme()) {
|
||||||
|
drawYapaCentreString(label, 175, 12, 4);
|
||||||
|
} else if (color == TFT_WHITE && isRainbowTheme()) {
|
||||||
|
drawRainbowCentreString(label.c_str(), 175, 12, 4);
|
||||||
|
} else {
|
||||||
tft.setTextColor(color);
|
tft.setTextColor(color);
|
||||||
tft.drawCentreString(label.c_str(), 175, 12, 4);
|
tft.drawCentreString(label.c_str(), 175, 12, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tactical ECO / OPT Badge (Ford Ka Endura 1.3 Sweet Spot: 1900 - 2550 RPM &
|
// Tactical ECO / OPT Badge (Ford Ka Endura 1.3 Sweet Spot: 1900 - 2550 RPM &
|
||||||
// 45% - 82% Load)
|
// 45% - 82% Load)
|
||||||
|
|
@ -1292,8 +1301,14 @@ void fullScreenMeter(uint8_t cell, uint8_t pid, bool redrawHeader = true) {
|
||||||
alarmEnabled[pid])
|
alarmEnabled[pid])
|
||||||
? TFT_RED
|
? TFT_RED
|
||||||
: TFT_WHITE;
|
: TFT_WHITE;
|
||||||
|
if (titleCol == TFT_WHITE && isYapaTheme()) {
|
||||||
|
drawYapaCentreString(label, 175, 12, 4);
|
||||||
|
} else if (titleCol == TFT_WHITE && isRainbowTheme()) {
|
||||||
|
drawRainbowCentreString(label.c_str(), 175, 12, 4);
|
||||||
|
} else {
|
||||||
tft.setTextColor(titleCol);
|
tft.setTextColor(titleCol);
|
||||||
tft.drawCentreString(label, 175, 12, 4);
|
tft.drawCentreString(label, 175, 12, 4);
|
||||||
|
}
|
||||||
if (cell == 1 && isGpsSpeedValid()) {
|
if (cell == 1 && isGpsSpeedValid()) {
|
||||||
drawFullscreenGpsIcon(getGpsWaveAnimState(), isGpsSynced());
|
drawFullscreenGpsIcon(getGpsWaveAnimState(), isGpsSynced());
|
||||||
}
|
}
|
||||||
|
|
@ -1750,8 +1765,12 @@ inline void renderPage1ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
||||||
s.setTextColor(TFT_WHITE, cardBg);
|
s.setTextColor(TFT_WHITE, cardBg);
|
||||||
s.drawString(titleStr, cardX + 16, cardY + 5, 4);
|
s.drawString(titleStr, cardX + 16, cardY + 5, 4);
|
||||||
}
|
}
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
drawYapaStringToSprite(s, subStr, cardX + 16, cardY + 32, 1);
|
||||||
|
} else {
|
||||||
s.setTextColor(0x8410, cardBg);
|
s.setTextColor(0x8410, cardBg);
|
||||||
s.drawString(subStr, cardX + 16, cardY + 32, 1);
|
s.drawString(subStr, cardX + 16, cardY + 32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Progress bar
|
// Progress bar
|
||||||
int barX = cardX + 16;
|
int barX = cardX + 16;
|
||||||
|
|
@ -1779,131 +1798,83 @@ inline void renderPage1ToSprite(TFT_eSprite &s, int x_offset, int y_slice,
|
||||||
|
|
||||||
int unitY = cardY + 22;
|
int unitY = cardY + 22;
|
||||||
if (unitY < slice_h && unitY + 26 > 0) {
|
if (unitY < slice_h && unitY + 26 > 0) {
|
||||||
draw7SegDegreeC(s, cardX + 268, unitY, 0xC618, cardBg);
|
bool rainbowUnit = isRainbowTheme() && (accentCol != TFT_RED);
|
||||||
|
uint16_t unitCol = rainbowUnit ? getRainbowScreenColor(cardX + 268, unitY) : (isYapaTheme() && accentCol != TFT_RED ? getYapaColor(numStr.length()) : (accentCol == TFT_RED ? TFT_RED : 0xC618));
|
||||||
|
draw7SegDegreeC(s, cardX + 268, unitY, unitCol, cardBg, rainbowUnit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 100% Flicker-Free Double-Buffered Mobile Slide Transition
|
// 100% Flicker-Free Backlight Dip / Fade-to-Black Transition
|
||||||
// Safe 25KB sprite with pixel-perfect clipping and smooth ease-out pacing
|
// Fades hardware backlight smoothly to black, renders the new page invisibly
|
||||||
inline void animateSlideTransition(bool swipeLeft, int8_t fromPage = -1,
|
// in the dark with zero tear, and smoothly restores backlight.
|
||||||
int8_t toPage = -1) {
|
inline void animateBlackTransition(int8_t toPage = -1) {
|
||||||
if (fromPage < 0)
|
|
||||||
fromPage = currentScreenPage;
|
|
||||||
if (toPage < 0)
|
if (toPage < 0)
|
||||||
toPage = (fromPage == 0) ? 1 : 0;
|
toPage = (currentScreenPage + 1) % 4;
|
||||||
#ifdef SERIAL_DEBUG
|
|
||||||
Serial.printf(">>> [DB] animateSlideTransition ENTER: fromPage=%d, "
|
|
||||||
"toPage=%d, swipeLeft=%d\n",
|
|
||||||
fromPage, toPage, swipeLeft);
|
|
||||||
#endif
|
|
||||||
const int slice_h = 40;
|
|
||||||
const uint8_t numSlices = 240 / slice_h; // exactly 6 slices
|
|
||||||
|
|
||||||
if (!sprTransAllocated) {
|
if (!sprTransAllocated) {
|
||||||
initScreen(true);
|
initScreen(true);
|
||||||
return; // Safety fallback
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t FRAMES = 28;
|
uint8_t startBrightness = (uint8_t)currentBacklight;
|
||||||
// High-density sine ease-out deceleration over 28 frames:
|
if (startBrightness < 20)
|
||||||
// Ultra-fine 10-18px initial steps smoothly tapering to 1-3px for zero
|
startBrightness = 20;
|
||||||
// visible refresh chop
|
|
||||||
const int16_t step_shifts[FRAMES] = {
|
|
||||||
18, 36, 54, 71, 89, 106, 122, 139, 155, 170, 185, 200, 213, 226,
|
|
||||||
239, 250, 261, 271, 280, 288, 296, 302, 307, 312, 315, 318, 319, 320};
|
|
||||||
|
|
||||||
for (uint8_t f = 0; f < FRAMES; f++) {
|
// 1. Smoothly fade backlight down to black in ~200ms (quadratic ease for natural eye response)
|
||||||
int16_t shift = step_shifts[f];
|
const uint8_t fadeSteps = 16;
|
||||||
int16_t splitX = swipeLeft ? (320 - shift) : shift;
|
for (int8_t i = fadeSteps - 1; i >= 0; i--) {
|
||||||
|
float t = (float)i / (float)fadeSteps;
|
||||||
|
uint8_t b = (uint8_t)(startBrightness * (t * t));
|
||||||
|
ledcWrite(backlightChannel, b);
|
||||||
|
delay(12);
|
||||||
|
}
|
||||||
|
ledcWrite(backlightChannel, 0);
|
||||||
|
|
||||||
|
// 2. Render new screen slice-by-slice while backlight is totally off (100% invisible redraw)
|
||||||
|
const int slice_h = 40;
|
||||||
|
const uint8_t numSlices = 240 / slice_h; // exactly 6 slices
|
||||||
for (uint8_t s = 0; s < numSlices; s++) {
|
for (uint8_t s = 0; s < numSlices; s++) {
|
||||||
int y_slice = s * slice_h;
|
int y_slice = s * slice_h;
|
||||||
|
|
||||||
sprTrans.fillSprite(TFT_BLACK);
|
sprTrans.fillSprite(TFT_BLACK);
|
||||||
|
|
||||||
if (swipeLeft) {
|
|
||||||
// Swipe Left: fromPage on left moving left, toPage on right moving left
|
|
||||||
if (splitX > 0) {
|
|
||||||
sprTrans.setViewport(0, 0, splitX, slice_h, false);
|
|
||||||
if (fromPage == 0)
|
|
||||||
renderPage0ToSprite(sprTrans, -shift, y_slice, slice_h);
|
|
||||||
else if (fromPage == 1)
|
|
||||||
renderPage1ToSprite(sprTrans, -shift, y_slice, slice_h);
|
|
||||||
else if (fromPage == 2)
|
|
||||||
renderPage2ToSprite(sprTrans, -shift, y_slice, slice_h);
|
|
||||||
else
|
|
||||||
renderPage3ToSprite(sprTrans, -shift, y_slice, slice_h);
|
|
||||||
}
|
|
||||||
if (splitX < 320) {
|
|
||||||
sprTrans.setViewport(splitX, 0, 320 - splitX, slice_h, false);
|
|
||||||
if (toPage == 0)
|
if (toPage == 0)
|
||||||
renderPage0ToSprite(sprTrans, 320 - shift, y_slice, slice_h);
|
renderPage0ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
else if (toPage == 1)
|
else if (toPage == 1)
|
||||||
renderPage1ToSprite(sprTrans, 320 - shift, y_slice, slice_h);
|
renderPage1ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
else if (toPage == 2)
|
else if (toPage == 2)
|
||||||
renderPage2ToSprite(sprTrans, 320 - shift, y_slice, slice_h);
|
renderPage2ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
|
else if (toPage == 3)
|
||||||
|
renderPage3ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
else
|
else
|
||||||
renderPage3ToSprite(sprTrans, 320 - shift, y_slice, slice_h);
|
renderPage4ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Swipe Right: toPage on left moving right, fromPage on right moving
|
|
||||||
// right
|
|
||||||
if (splitX > 0) {
|
|
||||||
sprTrans.setViewport(0, 0, splitX, slice_h, false);
|
|
||||||
if (toPage == 0)
|
|
||||||
renderPage0ToSprite(sprTrans, shift - 320, y_slice, slice_h);
|
|
||||||
else if (toPage == 1)
|
|
||||||
renderPage1ToSprite(sprTrans, shift - 320, y_slice, slice_h);
|
|
||||||
else if (toPage == 2)
|
|
||||||
renderPage2ToSprite(sprTrans, shift - 320, y_slice, slice_h);
|
|
||||||
else
|
|
||||||
renderPage3ToSprite(sprTrans, shift - 320, y_slice, slice_h);
|
|
||||||
}
|
|
||||||
if (splitX < 320) {
|
|
||||||
sprTrans.setViewport(splitX, 0, 320 - splitX, slice_h, false);
|
|
||||||
if (fromPage == 0)
|
|
||||||
renderPage0ToSprite(sprTrans, shift, y_slice, slice_h);
|
|
||||||
else if (fromPage == 1)
|
|
||||||
renderPage1ToSprite(sprTrans, shift, y_slice, slice_h);
|
|
||||||
else if (fromPage == 2)
|
|
||||||
renderPage2ToSprite(sprTrans, shift, y_slice, slice_h);
|
|
||||||
else
|
|
||||||
renderPage3ToSprite(sprTrans, shift, y_slice, slice_h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sprTrans.resetViewport();
|
|
||||||
|
|
||||||
// Dividing neon seam line
|
// Pagination indicator dots on top slice (5 dots for 5 pages)
|
||||||
if (splitX > 0 && splitX < 320) {
|
|
||||||
sprTrans.drawFastVLine(splitX, 0, slice_h, getThemePrimaryColor());
|
|
||||||
int16_t whiteLineX = splitX + (swipeLeft ? 1 : -1);
|
|
||||||
if (whiteLineX >= 0 && whiteLineX < 320) {
|
|
||||||
sprTrans.drawFastVLine(whiteLineX, 0, slice_h, TFT_WHITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pagination indicator dots on top slice (4 dots for 4 pages)
|
|
||||||
if (y_slice == 0) {
|
if (y_slice == 0) {
|
||||||
uint8_t activeDot = (shift < 160) ? fromPage : toPage;
|
sprTrans.fillCircle(132, 2, 2,
|
||||||
sprTrans.fillCircle(139, 2, 2,
|
(toPage == 0) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
(activeDot == 0) ? getThemePrimaryColor() : 0x5AEB);
|
sprTrans.fillCircle(146, 2, 2,
|
||||||
sprTrans.fillCircle(153, 2, 2,
|
(toPage == 1) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
(activeDot == 1) ? getThemePrimaryColor() : 0x5AEB);
|
sprTrans.fillCircle(160, 2, 2,
|
||||||
sprTrans.fillCircle(167, 2, 2,
|
(toPage == 2) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
(activeDot == 2) ? getThemePrimaryColor() : 0x5AEB);
|
sprTrans.fillCircle(174, 2, 2,
|
||||||
sprTrans.fillCircle(181, 2, 2,
|
(toPage == 3) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
(activeDot == 3) ? getThemePrimaryColor() : 0x5AEB);
|
sprTrans.fillCircle(188, 2, 2,
|
||||||
|
(toPage == 4) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct single SPI push per slice: ZERO visual flicker!
|
|
||||||
sprTrans.pushSprite(0, y_slice);
|
sprTrans.pushSprite(0, y_slice);
|
||||||
yield();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield(); // Feed watchdog and let Bluetooth run smoothly on background core
|
// 3. Smoothly fade backlight back up to original level in ~200ms
|
||||||
delay(7); // Ultra-smooth high density pacing (~330ms total)
|
for (uint8_t i = 1; i <= fadeSteps; i++) {
|
||||||
|
float t = (float)i / (float)fadeSteps;
|
||||||
|
uint8_t b = (uint8_t)(startBrightness * (t * t));
|
||||||
|
ledcWrite(backlightChannel, b);
|
||||||
|
delay(12);
|
||||||
}
|
}
|
||||||
|
currentBacklight = (float)startBrightness;
|
||||||
|
ledcWrite(backlightChannel, (uint32_t)targetBacklight);
|
||||||
|
|
||||||
sprTrans.fontLoaded = false;
|
sprTrans.fontLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1949,8 +1920,10 @@ inline void animateFadeTransition(int8_t fromPage = -1, int8_t toPage = -1) {
|
||||||
renderPage1ToSprite(sprTrans, 0, y_slice, slice_h);
|
renderPage1ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
else if (fromPage == 2)
|
else if (fromPage == 2)
|
||||||
renderPage2ToSprite(sprTrans, 0, y_slice, slice_h);
|
renderPage2ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
else
|
else if (fromPage == 3)
|
||||||
renderPage3ToSprite(sprTrans, 0, y_slice, slice_h);
|
renderPage3ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
|
else
|
||||||
|
renderPage4ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||||
|
|
||||||
if (toPage == 0)
|
if (toPage == 0)
|
||||||
renderPage0ToSprite(sprFadeB, 0, y_slice, slice_h);
|
renderPage0ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||||
|
|
@ -1958,8 +1931,10 @@ inline void animateFadeTransition(int8_t fromPage = -1, int8_t toPage = -1) {
|
||||||
renderPage1ToSprite(sprFadeB, 0, y_slice, slice_h);
|
renderPage1ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||||
else if (toPage == 2)
|
else if (toPage == 2)
|
||||||
renderPage2ToSprite(sprFadeB, 0, y_slice, slice_h);
|
renderPage2ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||||
else
|
else if (toPage == 3)
|
||||||
renderPage3ToSprite(sprFadeB, 0, y_slice, slice_h);
|
renderPage3ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||||
|
else
|
||||||
|
renderPage4ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||||
|
|
||||||
uint16_t *pA = (uint16_t *)sprTrans.getPointer();
|
uint16_t *pA = (uint16_t *)sprTrans.getPointer();
|
||||||
uint16_t *pB = (uint16_t *)sprFadeB.getPointer();
|
uint16_t *pB = (uint16_t *)sprFadeB.getPointer();
|
||||||
|
|
@ -1989,17 +1964,19 @@ inline void animateFadeTransition(int8_t fromPage = -1, int8_t toPage = -1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination indicator dots on top slice (4 dots for 4 pages)
|
// Pagination indicator dots on top slice (5 dots for 5 pages)
|
||||||
if (y_slice == 0) {
|
if (y_slice == 0) {
|
||||||
uint8_t activeDot = (alpha < 16) ? fromPage : toPage;
|
uint8_t activeDot = (alpha < 16) ? fromPage : toPage;
|
||||||
sprTrans.fillCircle(139, 2, 2,
|
sprTrans.fillCircle(132, 2, 2,
|
||||||
(activeDot == 0) ? getThemePrimaryColor() : 0x5AEB);
|
(activeDot == 0) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
sprTrans.fillCircle(153, 2, 2,
|
sprTrans.fillCircle(146, 2, 2,
|
||||||
(activeDot == 1) ? getThemePrimaryColor() : 0x5AEB);
|
(activeDot == 1) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
sprTrans.fillCircle(167, 2, 2,
|
sprTrans.fillCircle(160, 2, 2,
|
||||||
(activeDot == 2) ? getThemePrimaryColor() : 0x5AEB);
|
(activeDot == 2) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
sprTrans.fillCircle(181, 2, 2,
|
sprTrans.fillCircle(174, 2, 2,
|
||||||
(activeDot == 3) ? getThemePrimaryColor() : 0x5AEB);
|
(activeDot == 3) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
|
sprTrans.fillCircle(188, 2, 2,
|
||||||
|
(activeDot == 4) ? getThemePrimaryColor() : 0x5AEB);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprTrans.pushSprite(0, y_slice);
|
sprTrans.pushSprite(0, y_slice);
|
||||||
|
|
@ -2020,11 +1997,11 @@ inline void performScreenTransition(bool swipeLeft, int8_t fromPage = -1,
|
||||||
if (fromPage < 0)
|
if (fromPage < 0)
|
||||||
fromPage = currentScreenPage;
|
fromPage = currentScreenPage;
|
||||||
if (toPage < 0)
|
if (toPage < 0)
|
||||||
toPage = (fromPage + 1) % 4;
|
toPage = (fromPage + 1) % 5;
|
||||||
if (transitionType == 1) {
|
if (transitionType == 1) {
|
||||||
animateFadeTransition(fromPage, toPage);
|
animateFadeTransition(fromPage, toPage);
|
||||||
} else {
|
} else {
|
||||||
animateSlideTransition(swipeLeft, fromPage, toPage);
|
animateBlackTransition(toPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2059,6 +2036,8 @@ void initScreen(bool redrawTFT) {
|
||||||
syncGpsClockTrackers();
|
syncGpsClockTrackers();
|
||||||
} else if (currentScreenPage == 3) {
|
} else if (currentScreenPage == 3) {
|
||||||
syncGpsNavTrackers();
|
syncGpsNavTrackers();
|
||||||
|
} else if (currentScreenPage == 4) {
|
||||||
|
syncClusterTrackers();
|
||||||
} else if (currentScreenPage == 0 && fullScreenCell == -1) {
|
} else if (currentScreenPage == 0 && fullScreenCell == -1) {
|
||||||
syncPage0Trackers();
|
syncPage0Trackers();
|
||||||
}
|
}
|
||||||
|
|
@ -2093,6 +2072,11 @@ void initScreen(bool redrawTFT) {
|
||||||
Serial.println(">>> [DB] initScreen: drawing drawGpsNavScreen(0)");
|
Serial.println(">>> [DB] initScreen: drawing drawGpsNavScreen(0)");
|
||||||
#endif
|
#endif
|
||||||
drawGpsNavScreen(0);
|
drawGpsNavScreen(0);
|
||||||
|
} else if (currentScreenPage == 4) {
|
||||||
|
#ifdef SERIAL_DEBUG
|
||||||
|
Serial.println(">>> [DB] initScreen: drawing drawClusterScreen(0)");
|
||||||
|
#endif
|
||||||
|
drawClusterScreen(0);
|
||||||
} else {
|
} else {
|
||||||
#ifdef SERIAL_DEBUG
|
#ifdef SERIAL_DEBUG
|
||||||
Serial.println(">>> [DB] initScreen: drawing Page 0 quadrants");
|
Serial.println(">>> [DB] initScreen: drawing Page 0 quadrants");
|
||||||
|
|
@ -2103,11 +2087,12 @@ void initScreen(bool redrawTFT) {
|
||||||
arcMeter4(c, pid);
|
arcMeter4(c, pid);
|
||||||
}
|
}
|
||||||
drawQuadrantDividers();
|
drawQuadrantDividers();
|
||||||
// Pagination indicator dots [● ○ ○ ○] (Page 1 active)
|
// Pagination indicator dots [● ○ ○ ○ ○] (Page 0 active)
|
||||||
tft.fillCircle(139, 2, 2, getThemePrimaryColor()); // Page 1 active
|
tft.fillCircle(132, 2, 2, getThemePrimaryColor());
|
||||||
tft.fillCircle(153, 2, 2, 0x5AEB); // Page 2 inactive
|
tft.fillCircle(146, 2, 2, 0x5AEB);
|
||||||
tft.fillCircle(167, 2, 2, 0x5AEB); // Page 3 inactive
|
tft.fillCircle(160, 2, 2, 0x5AEB);
|
||||||
tft.fillCircle(181, 2, 2, 0x5AEB); // Page 4 inactive
|
tft.fillCircle(174, 2, 2, 0x5AEB);
|
||||||
|
tft.fillCircle(188, 2, 2, 0x5AEB);
|
||||||
}
|
}
|
||||||
if (currentScreenPage == 0 && fullScreenCell == -1) {
|
if (currentScreenPage == 0 && fullScreenCell == -1) {
|
||||||
badgeEcoDrawn = false;
|
badgeEcoDrawn = false;
|
||||||
|
|
@ -2441,6 +2426,8 @@ void updateMeter(uint8_t pidNo, String response) { // update parameter on screen
|
||||||
}
|
}
|
||||||
} else if (currentScreenPage == 0) {
|
} else if (currentScreenPage == 0) {
|
||||||
plotArc4(pidNo, data, warn, min, max, digit, unit);
|
plotArc4(pidNo, data, warn, min, max, digit, unit);
|
||||||
|
} else if (currentScreenPage == 4) {
|
||||||
|
updateClusterScreen(false);
|
||||||
}
|
}
|
||||||
bt_message = ""; // reset
|
bt_message = ""; // reset
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ struct GaugeTheme {
|
||||||
uint8_t ledB; // Rear RGB LED Blue (0..255)
|
uint8_t ledB; // Rear RGB LED Blue (0..255)
|
||||||
};
|
};
|
||||||
|
|
||||||
const GaugeTheme GAUGE_THEMES[6] = {
|
const GaugeTheme GAUGE_THEMES[9] = {
|
||||||
{"Azul Cian", "Digital Moderno", 0x07FF, 0x03B9, 0x0254, 0x0110, 0x01D3, 0,
|
{"Azul Cian", "Digital Moderno", 0x07FF, 0x03B9, 0x0254, 0x0110, 0x01D3, 0,
|
||||||
180, 255}, // 0: Vivid Electric Cyan
|
180, 255}, // 0: Vivid Electric Cyan
|
||||||
{"Verde Sport", "Cockpit Clasico", 0x07E0, 0x0446, 0x0283, 0x0141, 0x0205,
|
{"Verde Sport", "Cockpit Clasico", 0x07E0, 0x0446, 0x0283, 0x0141, 0x0205,
|
||||||
|
|
@ -136,47 +136,54 @@ const GaugeTheme GAUGE_THEMES[6] = {
|
||||||
{"Blanco Puro", "OLED Precision", 0xFFFF, 0x6B6D, 0x4228, 0x18E3, 0x2965,
|
{"Blanco Puro", "OLED Precision", 0xFFFF, 0x6B6D, 0x4228, 0x18E3, 0x2965,
|
||||||
220, 230, 255}, // 3: Pure Crisp White
|
220, 230, 255}, // 3: Pure Crisp White
|
||||||
{"Naranja Sport", "McLaren Papaya", 0xFD20, 0x9260, 0x5160, 0x20A0, 0x4140,
|
{"Naranja Sport", "McLaren Papaya", 0xFD20, 0x9260, 0x5160, 0x20A0, 0x4140,
|
||||||
255, 80, 0}, // 4: Vivid Papaya Orange (reemplaza rojo)
|
255, 80, 0}, // 4: Vivid Papaya Orange
|
||||||
{"Cyber Violet", "Neon Nightrunner", 0xD1BF, 0x7119, 0x40CE, 0x1846, 0x2869,
|
{"Cyber Violet", "Neon Nightrunner", 0xD1BF, 0x7119, 0x40CE, 0x1846, 0x2869,
|
||||||
200, 0, 255} // 5: Vivid Electric Violet
|
200, 0, 255}, // 5: Vivid Electric Violet
|
||||||
|
{"Rojo Corsa", "Pasion Italiana", 0xF800, 0x8800, 0x5000, 0x2000, 0x3800,
|
||||||
|
255, 0, 0}, // 6: Vivid Racing Red
|
||||||
|
{"Ambar BMW", "Cockpit Nocturno", 0xFD60, 0x9380, 0x5240, 0x2100, 0x39A0,
|
||||||
|
255, 120, 0}, // 7: Warm Golden Amber (BMW classic)
|
||||||
|
{"Yapa", "Pastillas Pastel", 0xFD79, 0x3A53, 0x52AA, 0x18E5, 0x2168,
|
||||||
|
255, 190, 220} // 8: Pastillas Yapa Pastel Candies
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t themeIndex = 0; // Default 0: Azul Cian
|
uint8_t themeIndex = 0; // Default 0: Azul Cian
|
||||||
uint8_t transitionType =
|
uint8_t transitionType =
|
||||||
1; // Default 1: Desvanecimiento (Fade), 0: Deslizamiento (Slide)
|
0; // Default 0: Fundido a Negro (Fade to Black), 1: Desvanecimiento (Fade)
|
||||||
|
|
||||||
inline uint16_t getThemePrimaryColor() {
|
inline uint16_t getThemePrimaryColor() {
|
||||||
if (themeIndex >= 6)
|
if (themeIndex >= 9)
|
||||||
return 0x07FF;
|
return 0x07FF;
|
||||||
return GAUGE_THEMES[themeIndex].primaryColor;
|
return GAUGE_THEMES[themeIndex].primaryColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t getThemeAccentColor() {
|
inline uint16_t getThemeAccentColor() {
|
||||||
if (themeIndex >= 6)
|
if (themeIndex >= 9)
|
||||||
return 0x234F;
|
return 0x234F;
|
||||||
return GAUGE_THEMES[themeIndex].accentColor;
|
return GAUGE_THEMES[themeIndex].accentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t getThemeDivColor() {
|
inline uint16_t getThemeDivColor() {
|
||||||
if (themeIndex >= 6)
|
if (themeIndex >= 9)
|
||||||
return 0x3412;
|
return 0x3412;
|
||||||
return GAUGE_THEMES[themeIndex].divColor;
|
return GAUGE_THEMES[themeIndex].divColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t getThemeDarkColor() {
|
inline uint16_t getThemeDarkColor() {
|
||||||
if (themeIndex >= 6)
|
if (themeIndex >= 9)
|
||||||
return 0x1105;
|
return 0x1105;
|
||||||
return GAUGE_THEMES[themeIndex].darkColor;
|
return GAUGE_THEMES[themeIndex].darkColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t getThemeBgColor() {
|
inline uint16_t getThemeBgColor() {
|
||||||
if (themeIndex >= 6)
|
if (themeIndex >= 9)
|
||||||
return 0x19C8;
|
return 0x19C8;
|
||||||
return GAUGE_THEMES[themeIndex].bgColor;
|
return GAUGE_THEMES[themeIndex].bgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rainbow theme helpers (theme index 2)
|
// Special theme helpers
|
||||||
inline bool isRainbowTheme() { return themeIndex == 2; }
|
inline bool isRainbowTheme() { return themeIndex == 2; }
|
||||||
|
inline bool isYapaTheme() { return themeIndex == 8; }
|
||||||
|
|
||||||
// Convert hue (0..359, full saturation/value) to RGB565
|
// Convert hue (0..359, full saturation/value) to RGB565
|
||||||
inline uint16_t hueToRgb565(uint16_t hue) {
|
inline uint16_t hueToRgb565(uint16_t hue) {
|
||||||
|
|
@ -249,6 +256,10 @@ inline uint16_t getThemeCellColor(uint8_t cell) {
|
||||||
if (isRainbowTheme()) {
|
if (isRainbowTheme()) {
|
||||||
return getRainbowCellColor(cell);
|
return getRainbowCellColor(cell);
|
||||||
}
|
}
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
const uint16_t yapaCell[4] = { 0xFD79, 0x971F, 0xFFF2, 0xA7D7 };
|
||||||
|
return yapaCell[cell % 4];
|
||||||
|
}
|
||||||
return getThemePrimaryColor();
|
return getThemePrimaryColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,8 +301,8 @@ int8_t currentScreenPage =
|
||||||
inline void setScreenPage(int8_t page) {
|
inline void setScreenPage(int8_t page) {
|
||||||
if (page < 0)
|
if (page < 0)
|
||||||
page = 0;
|
page = 0;
|
||||||
if (page > 3)
|
if (page > 4)
|
||||||
page = 3;
|
page = 4;
|
||||||
currentScreenPage = page;
|
currentScreenPage = page;
|
||||||
pref.begin("setting", false);
|
pref.begin("setting", false);
|
||||||
pref.putChar("scr_page", page);
|
pref.putChar("scr_page", page);
|
||||||
|
|
@ -321,8 +332,8 @@ const uint8_t MAX_TERMINAL_LINES = 13;
|
||||||
String line[MAX_TERMINAL_LINES]; // buffer for each line in terminal function
|
String line[MAX_TERMINAL_LINES]; // buffer for each line in terminal function
|
||||||
uint8_t terminalLineCount = 0;
|
uint8_t terminalLineCount = 0;
|
||||||
bool dim = false; // back light dim flag
|
bool dim = false; // back light dim flag
|
||||||
const uint8_t LIGHT_LEVEL =
|
const uint16_t LIGHT_LEVEL =
|
||||||
40; // backlight control by light level Higher = darker light
|
1000; // Umbral de luz ambiental dia/noche para ADC de 12 bits (0..4095)
|
||||||
|
|
||||||
// BLUETOOTH
|
// BLUETOOTH
|
||||||
String bt_message = ""; // bluetooth message buffer
|
String bt_message = ""; // bluetooth message buffer
|
||||||
|
|
@ -477,6 +488,7 @@ String sendATCommand(const String &cmd, uint32_t timeoutMs = 2000) {
|
||||||
#include "gps_module.h"
|
#include "gps_module.h"
|
||||||
#include "gps_clock.h"
|
#include "gps_clock.h"
|
||||||
#include "gps_nav.h"
|
#include "gps_nav.h"
|
||||||
|
#include "cluster_screen.h"
|
||||||
#include "meter.h"
|
#include "meter.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
@ -693,13 +705,13 @@ recent_client_addr : {0x00,0x00,0x00,0x00,0x00,0x00} array of bytes[6]
|
||||||
if (brightnessIndex > 5)
|
if (brightnessIndex > 5)
|
||||||
brightnessIndex = 0;
|
brightnessIndex = 0;
|
||||||
themeIndex = pref.getUChar("theme_idx", 0);
|
themeIndex = pref.getUChar("theme_idx", 0);
|
||||||
if (themeIndex > 5)
|
if (themeIndex > 8)
|
||||||
themeIndex = 0;
|
themeIndex = 0;
|
||||||
transitionType = pref.getUChar("trans_type", 1);
|
transitionType = pref.getUChar("trans_type", 0);
|
||||||
if (transitionType > 1)
|
if (transitionType > 1)
|
||||||
transitionType = 1;
|
transitionType = 0;
|
||||||
currentScreenPage = pref.getChar("scr_page", 0);
|
currentScreenPage = pref.getChar("scr_page", 0);
|
||||||
if (currentScreenPage < 0 || currentScreenPage > 3)
|
if (currentScreenPage < 0 || currentScreenPage > 4)
|
||||||
currentScreenPage = 0;
|
currentScreenPage = 0;
|
||||||
if (brightnessIndex > 0) {
|
if (brightnessIndex > 0) {
|
||||||
targetBacklight = BRIGHTNESS_PWM_TABLE[brightnessIndex];
|
targetBacklight = BRIGHTNESS_PWM_TABLE[brightnessIndex];
|
||||||
|
|
@ -714,7 +726,7 @@ recent_client_addr : {0x00,0x00,0x00,0x00,0x00,0x00} array of bytes[6]
|
||||||
Terminal("[ OK ] Settings: Theme " + String(GAUGE_THEMES[themeIndex].name) +
|
Terminal("[ OK ] Settings: Theme " + String(GAUGE_THEMES[themeIndex].name) +
|
||||||
" (LED RGB)");
|
" (LED RGB)");
|
||||||
Terminal("[ OK ] Settings: Transicion " +
|
Terminal("[ OK ] Settings: Transicion " +
|
||||||
String(transitionType == 0 ? "Deslizamiento" : "Desvanecimiento"));
|
String(transitionType == 0 ? "Fundido a Negro" : "Desvanecimiento"));
|
||||||
delay(40);
|
delay(40);
|
||||||
|
|
||||||
// Initialize persistent transition sprites (pre-allocated once at boot in clean heap)
|
// Initialize persistent transition sprites (pre-allocated once at boot in clean heap)
|
||||||
|
|
@ -851,6 +863,11 @@ void loop() {
|
||||||
updateGpsNavScreen(false);
|
updateGpsNavScreen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-blocking live refresh for resting Page 4 (Cockpit Instrumental Deportivo)
|
||||||
|
if (currentScreenPage == 4 && fullScreenCell == -1) {
|
||||||
|
updateClusterScreen(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (wokeFromSleep) {
|
if (wokeFromSleep) {
|
||||||
wokeFromSleep = false;
|
wokeFromSleep = false;
|
||||||
lastActivityTime = millis();
|
lastActivityTime = millis();
|
||||||
|
|
@ -910,10 +927,10 @@ void loop() {
|
||||||
// (disabled in full-screen mode)
|
// (disabled in full-screen mode)
|
||||||
if (!longPressHandled) {
|
if (!longPressHandled) {
|
||||||
if (fullScreenCell == -1 && liveDeltaX < -28 && abs(liveDeltaY) < 85) {
|
if (fullScreenCell == -1 && liveDeltaX < -28 && abs(liveDeltaY) < 85) {
|
||||||
// SWIPE LEFT: Transition to next page (0 -> 1 -> 2 -> 3 -> 0)
|
// SWIPE LEFT: Transition to next page (0 -> 1 -> 2 -> 3 -> 4 -> 0)
|
||||||
longPressHandled = true;
|
longPressHandled = true;
|
||||||
touchBeep();
|
touchBeep();
|
||||||
uint8_t nextPage = (currentScreenPage + 1) % 4;
|
uint8_t nextPage = (currentScreenPage + 1) % 5;
|
||||||
performScreenTransition(true, currentScreenPage, nextPage);
|
performScreenTransition(true, currentScreenPage, nextPage);
|
||||||
setScreenPage(nextPage);
|
setScreenPage(nextPage);
|
||||||
initScreen(false); // Seamless: keep transition frame without blanking
|
initScreen(false); // Seamless: keep transition frame without blanking
|
||||||
|
|
@ -923,11 +940,11 @@ void loop() {
|
||||||
lastActivityTime = millis();
|
lastActivityTime = millis();
|
||||||
} else if (fullScreenCell == -1 && liveDeltaX > 28 &&
|
} else if (fullScreenCell == -1 && liveDeltaX > 28 &&
|
||||||
abs(liveDeltaY) < 85) {
|
abs(liveDeltaY) < 85) {
|
||||||
// SWIPE RIGHT: Transition to previous page (0 -> 3 -> 2 -> 1 -> 0)
|
// SWIPE RIGHT: Transition to previous page (0 -> 4 -> 3 -> 2 -> 1 -> 0)
|
||||||
longPressHandled = true;
|
longPressHandled = true;
|
||||||
touchBeep();
|
touchBeep();
|
||||||
uint8_t nextPage =
|
uint8_t nextPage =
|
||||||
(currentScreenPage == 0) ? 3 : (currentScreenPage - 1);
|
(currentScreenPage == 0) ? 4 : (currentScreenPage - 1);
|
||||||
performScreenTransition(false, currentScreenPage, nextPage);
|
performScreenTransition(false, currentScreenPage, nextPage);
|
||||||
setScreenPage(nextPage);
|
setScreenPage(nextPage);
|
||||||
initScreen(false); // Seamless: keep transition frame without blanking
|
initScreen(false); // Seamless: keep transition frame without blanking
|
||||||
|
|
@ -967,7 +984,7 @@ void loop() {
|
||||||
// SWIPE LEFT
|
// SWIPE LEFT
|
||||||
longPressHandled = true;
|
longPressHandled = true;
|
||||||
touchBeep();
|
touchBeep();
|
||||||
uint8_t nextPage = (currentScreenPage + 1) % 4;
|
uint8_t nextPage = (currentScreenPage + 1) % 5;
|
||||||
performScreenTransition(true, currentScreenPage, nextPage);
|
performScreenTransition(true, currentScreenPage, nextPage);
|
||||||
setScreenPage(nextPage);
|
setScreenPage(nextPage);
|
||||||
initScreen(false); // Seamless: keep transition frame without blanking
|
initScreen(false); // Seamless: keep transition frame without blanking
|
||||||
|
|
@ -980,7 +997,7 @@ void loop() {
|
||||||
longPressHandled = true;
|
longPressHandled = true;
|
||||||
touchBeep();
|
touchBeep();
|
||||||
uint8_t nextPage =
|
uint8_t nextPage =
|
||||||
(currentScreenPage == 0) ? 3 : (currentScreenPage - 1);
|
(currentScreenPage == 0) ? 4 : (currentScreenPage - 1);
|
||||||
performScreenTransition(false, currentScreenPage, nextPage);
|
performScreenTransition(false, currentScreenPage, nextPage);
|
||||||
setScreenPage(nextPage);
|
setScreenPage(nextPage);
|
||||||
initScreen(false); // Seamless: keep transition frame without blanking
|
initScreen(false); // Seamless: keep transition frame without blanking
|
||||||
|
|
@ -1012,6 +1029,9 @@ void loop() {
|
||||||
} else if (currentScreenPage == 3) {
|
} else if (currentScreenPage == 3) {
|
||||||
// Tap on GPS Navigation screen: immediate telemetry refresh
|
// Tap on GPS Navigation screen: immediate telemetry refresh
|
||||||
updateGpsNavScreen(true);
|
updateGpsNavScreen(true);
|
||||||
|
} else if (currentScreenPage == 4) {
|
||||||
|
// Tap on Cockpit Instrumental: immediate cluster refresh
|
||||||
|
updateClusterScreen(true);
|
||||||
}
|
}
|
||||||
waitForTouchRelease();
|
waitForTouchRelease();
|
||||||
lastActivityTime = millis();
|
lastActivityTime = millis();
|
||||||
|
|
@ -1035,6 +1055,14 @@ void loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AUTO-DIM BACKLIGHT: Control continuo de brillo en todas las pantallas
|
||||||
|
// Funciona siempre, este o no conectado el Bluetooth
|
||||||
|
static uint32_t lastContinuousDimCheck = 0;
|
||||||
|
if (millis() - lastContinuousDimCheck >= 50) {
|
||||||
|
lastContinuousDimCheck = millis();
|
||||||
|
autoDim();
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SKIP_CONNECTION
|
#ifndef SKIP_CONNECTION
|
||||||
// Check Bluetooth connection state: if adapter disconnected or lost power,
|
// Check Bluetooth connection state: if adapter disconnected or lost power,
|
||||||
// switch immediately to GPS Clock Screen (Page 2) and show "---" on OBD
|
// switch immediately to GPS Clock Screen (Page 2) and show "---" on OBD
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -49,12 +49,12 @@ inline bool isScreenPressed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until both touchscreen and selector button are completely released with
|
// Wait until both touchscreen and selector button are completely released with
|
||||||
// 30ms continuous debounce and 250ms maximum hardware safety timeout
|
// 30ms continuous debounce and 4000ms maximum hardware safety timeout
|
||||||
inline void waitForTouchRelease() {
|
inline void waitForTouchRelease(uint32_t maxWaitMs = 4000) {
|
||||||
uint16_t dummyX, dummyY;
|
uint16_t dummyX, dummyY;
|
||||||
uint8_t releaseCount = 0;
|
uint8_t releaseCount = 0;
|
||||||
uint32_t startWait = millis();
|
uint32_t startWait = millis();
|
||||||
while (releaseCount < 3 && (millis() - startWait < 250)) {
|
while (releaseCount < 3 && (millis() - startWait < maxWaitMs)) {
|
||||||
if (getTouch(&dummyX, &dummyY) || (digitalRead(SELECTOR_PIN) == LOW)) {
|
if (getTouch(&dummyX, &dummyY) || (digitalRead(SELECTOR_PIN) == LOW)) {
|
||||||
releaseCount = 0;
|
releaseCount = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ static uint8_t oldTriDsSensorCount = 255;
|
||||||
static TFT_eSprite sprTriTitle[3] = { TFT_eSprite(&tft), TFT_eSprite(&tft), TFT_eSprite(&tft) };
|
static TFT_eSprite sprTriTitle[3] = { TFT_eSprite(&tft), TFT_eSprite(&tft), TFT_eSprite(&tft) };
|
||||||
static bool sprTriTitleReady = false;
|
static bool sprTriTitleReady = false;
|
||||||
|
|
||||||
|
inline void invalidateTriTempTitles() {
|
||||||
|
sprTriTitleReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
inline void initTriTempTitles() {
|
inline void initTriTempTitles() {
|
||||||
if (sprTriTitleReady) return;
|
if (sprTriTitleReady) return;
|
||||||
uint16_t cardBg = 0x10A2;
|
uint16_t cardBg = 0x10A2;
|
||||||
|
|
@ -57,8 +61,20 @@ inline void initTriTempTitles() {
|
||||||
sprTriTitle[i].loadFont(Latin_Sans_Bold_26);
|
sprTriTitle[i].loadFont(Latin_Sans_Bold_26);
|
||||||
sprTriTitle[i].setTextPadding(0);
|
sprTriTitle[i].setTextPadding(0);
|
||||||
sprTriTitle[i].fillSprite(cardBg);
|
sprTriTitle[i].fillSprite(cardBg);
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
int curX = 0;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
String t = titles[i];
|
||||||
|
for (size_t k = 0; k < t.length(); k++) {
|
||||||
|
buf[0] = t[k];
|
||||||
|
sprTriTitle[i].setTextColor(getYapaColor(k), cardBg);
|
||||||
|
sprTriTitle[i].drawString(buf, curX, 0);
|
||||||
|
curX += sprTriTitle[i].textWidth(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
sprTriTitle[i].setTextColor(TFT_WHITE, cardBg);
|
sprTriTitle[i].setTextColor(TFT_WHITE, cardBg);
|
||||||
sprTriTitle[i].drawString(titles[i], 0, 0, 1);
|
sprTriTitle[i].drawString(titles[i], 0, 0, 1);
|
||||||
|
}
|
||||||
sprTriTitle[i].unloadFont();
|
sprTriTitle[i].unloadFont();
|
||||||
if (isRainbowTheme()) {
|
if (isRainbowTheme()) {
|
||||||
applyRainbowToSprite(sprTriTitle[i], 4 + 16, 19 + i * 74 + 5, cardBg);
|
applyRainbowToSprite(sprTriTitle[i], 4 + 16, 19 + i * 74 + 5, cardBg);
|
||||||
|
|
@ -141,7 +157,7 @@ const uint8_t s_dsegUnitAlpha[30 * 26] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Draw 100% anti-aliased digital 7-segment italic unit "°C" matching DSEG7 typography and color
|
// Draw 100% anti-aliased digital 7-segment italic unit "°C" matching DSEG7 typography and color
|
||||||
inline void draw7SegDegreeC(TFT_eSPI &dst, int bx, int by, uint16_t color = 0xC618, uint16_t bgCol = 0x10A2) {
|
inline void draw7SegDegreeC(TFT_eSPI &dst, int bx, int by, uint16_t color = 0xC618, uint16_t bgCol = 0x10A2, bool rainbow = false) {
|
||||||
for (int j = 0; j < 26; j++) {
|
for (int j = 0; j < 26; j++) {
|
||||||
int py = by + j;
|
int py = by + j;
|
||||||
if (py < 0 || py >= dst.height()) continue;
|
if (py < 0 || py >= dst.height()) continue;
|
||||||
|
|
@ -151,7 +167,8 @@ inline void draw7SegDegreeC(TFT_eSPI &dst, int bx, int by, uint16_t color = 0xC6
|
||||||
if (px < 0 || px >= dst.width()) continue;
|
if (px < 0 || px >= dst.width()) continue;
|
||||||
uint8_t a = pgm_read_byte(&s_dsegUnitAlpha[rowOffset + i]);
|
uint8_t a = pgm_read_byte(&s_dsegUnitAlpha[rowOffset + i]);
|
||||||
if (a > 8) {
|
if (a > 8) {
|
||||||
uint16_t pixCol = (a >= 250) ? color : fastBlend(a, color, bgCol);
|
uint16_t curCol = rainbow ? getRainbowScreenColor(px, py) : color;
|
||||||
|
uint16_t pixCol = (a >= 250) ? curCol : fastBlend(a, curCol, bgCol);
|
||||||
dst.drawPixel(px, py, pixCol);
|
dst.drawPixel(px, py, pixCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +242,7 @@ inline void drawTriTempCard(uint8_t cardIdx, float val, int x_offset = 0) {
|
||||||
isInt = true;
|
isInt = true;
|
||||||
float warnT = warningValue[0].toFloat();
|
float warnT = warningValue[0].toFloat();
|
||||||
if (warnT <= 0) warnT = 110.0f;
|
if (warnT <= 0) warnT = 110.0f;
|
||||||
if (val < (warnT - 10.0f)) accentCol = isRainbowTheme() ? (uint16_t)0x07FF : getThemePrimaryColor();
|
if (val < (warnT - 10.0f)) accentCol = isRainbowTheme() ? (uint16_t)0x07FF : (isYapaTheme() ? getYapaColor(0) : getThemePrimaryColor());
|
||||||
else if (val < warnT) accentCol = TFT_YELLOW;
|
else if (val < warnT) accentCol = TFT_YELLOW;
|
||||||
else accentCol = TFT_RED;
|
else accentCol = TFT_RED;
|
||||||
} else if (cardIdx == 1) {
|
} else if (cardIdx == 1) {
|
||||||
|
|
@ -233,19 +250,43 @@ inline void drawTriTempCard(uint8_t cardIdx, float val, int x_offset = 0) {
|
||||||
subStr = (dsSensorCount > 0) ? "DS18B20 SENSOR 1 (GPIO 22)" : "DS18B20 SENSOR 1";
|
subStr = (dsSensorCount > 0) ? "DS18B20 SENSOR 1 (GPIO 22)" : "DS18B20 SENSOR 1";
|
||||||
minRange = 10.0f;
|
minRange = 10.0f;
|
||||||
maxRange = 40.0f;
|
maxRange = 40.0f;
|
||||||
accentCol = isRainbowTheme() ? (uint16_t)0x07E0 : getThemeAccentColor(); // Green in rainbow
|
accentCol = isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : getThemeAccentColor());
|
||||||
} else {
|
} else {
|
||||||
titleStr = "EXTERIOR";
|
titleStr = "EXTERIOR";
|
||||||
subStr = (dsSensorCount > 1) ? "DS18B20 SENSOR 2 (GPIO 22)" : (dsSensorCount == 1 ? "ESTIMADA (-4.5`C)" : "DS18B20 SENSOR 2");
|
subStr = (dsSensorCount > 1) ? "DS18B20 SENSOR 2 (GPIO 22)" : (dsSensorCount == 1 ? "ESTIMADA (-4.5`C)" : "DS18B20 SENSOR 2");
|
||||||
minRange = -10.0f;
|
minRange = -10.0f;
|
||||||
maxRange = 50.0f;
|
maxRange = 50.0f;
|
||||||
accentCol = isRainbowTheme() ? (uint16_t)0xFD20 : getThemePrimaryColor(); // Orange in rainbow
|
accentCol = isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(2) : getThemePrimaryColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Left vertical accent bar
|
// Left vertical accent bar
|
||||||
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
||||||
|
|
||||||
// Titles (Smooth anti-aliased font)
|
if (isYapaTheme()) {
|
||||||
|
tft.loadFont(Latin_Sans_Bold_26);
|
||||||
|
int curX = cardX + 16;
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
uint8_t cIdx = 0;
|
||||||
|
for (int i = 0; titleStr[i] != '\0'; i++) {
|
||||||
|
char c = titleStr[i];
|
||||||
|
buf[0] = c;
|
||||||
|
if (c == ' ') { curX += tft.textWidth(buf); continue; }
|
||||||
|
tft.setTextColor(getYapaColor(cIdx++), cardBg);
|
||||||
|
tft.drawString(buf, curX, cardY + 5);
|
||||||
|
curX += tft.textWidth(buf);
|
||||||
|
}
|
||||||
|
tft.unloadFont();
|
||||||
|
int sX = cardX + 16;
|
||||||
|
for (int i = 0; subStr[i] != '\0'; i++) {
|
||||||
|
char c = subStr[i];
|
||||||
|
buf[0] = c;
|
||||||
|
int cw = tft.textWidth(buf, 1);
|
||||||
|
if (c == ' ') { sX += cw; continue; }
|
||||||
|
tft.setTextColor(getYapaColor(cIdx++), cardBg);
|
||||||
|
tft.drawString(buf, sX, cardY + 32, 1);
|
||||||
|
sX += cw;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (!sprTriTitleReady) initTriTempTitles();
|
if (!sprTriTitleReady) initTriTempTitles();
|
||||||
if (sprTriTitleReady && sprTriTitle[cardIdx].created()) {
|
if (sprTriTitleReady && sprTriTitle[cardIdx].created()) {
|
||||||
sprTriTitle[cardIdx].pushSprite(cardX + 16, cardY + 5);
|
sprTriTitle[cardIdx].pushSprite(cardX + 16, cardY + 5);
|
||||||
|
|
@ -259,6 +300,7 @@ inline void drawTriTempCard(uint8_t cardIdx, float val, int x_offset = 0) {
|
||||||
|
|
||||||
tft.setTextColor(0x8410, cardBg); // Soft gray
|
tft.setTextColor(0x8410, cardBg); // Soft gray
|
||||||
tft.drawString(subStr, cardX + 16, cardY + 32, 1);
|
tft.drawString(subStr, cardX + 16, cardY + 32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Horizontal Progress Gauge Bar
|
// 3. Horizontal Progress Gauge Bar
|
||||||
int barX = cardX + 16;
|
int barX = cardX + 16;
|
||||||
|
|
@ -294,7 +336,9 @@ inline void drawTriTempCard(uint8_t cardIdx, float val, int x_offset = 0) {
|
||||||
drawDseg7RightString34(tft, numStr.c_str(), cardX + 262, cardY + 20, accentCol, cardBg, 100, 240, rainbowTxt);
|
drawDseg7RightString34(tft, numStr.c_str(), cardX + 262, cardY + 20, accentCol, cardBg, 100, 240, rainbowTxt);
|
||||||
|
|
||||||
// Unit "°C" in authentic digital 7-segment italic typography matching numbers
|
// Unit "°C" in authentic digital 7-segment italic typography matching numbers
|
||||||
draw7SegDegreeC(tft, cardX + 268, cardY + 22, isRainbowTheme() ? getRainbowScreenColor(cardX + 268, cardY + 22) : 0xC618, cardBg);
|
bool rainbowUnit = isRainbowTheme() && (accentCol != TFT_RED);
|
||||||
|
uint16_t unitCol = rainbowUnit ? getRainbowScreenColor(cardX + 268, cardY + 22) : (isYapaTheme() && accentCol != TFT_RED ? getYapaColor(numStr.length()) : (accentCol == TFT_RED ? TFT_RED : 0xC618));
|
||||||
|
draw7SegDegreeC(tft, cardX + 268, cardY + 22, unitCol, cardBg, rainbowUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flicker-free dynamic value update for a single temperature card
|
// Flicker-free dynamic value update for a single temperature card
|
||||||
|
|
@ -330,24 +374,42 @@ inline void updateTriTempCardValue(uint8_t cardIdx, float val, float oldVal) {
|
||||||
oldTriIgnition = ignitionOn;
|
oldTriIgnition = ignitionOn;
|
||||||
const char* subStr = ignitionOn ? "ECU OBD-II (PID 0105)" : "ECU OBD-II (STANDBY)";
|
const char* subStr = ignitionOn ? "ECU OBD-II (PID 0105)" : "ECU OBD-II (STANDBY)";
|
||||||
tft.fillRect(cardX + 16, cardY + 32, 130, 10, cardBg);
|
tft.fillRect(cardX + 16, cardY + 32, 130, 10, cardBg);
|
||||||
|
if (isYapaTheme()) {
|
||||||
|
char buf[2] = {0, 0};
|
||||||
|
int sX = cardX + 16;
|
||||||
|
uint8_t cIdx = 4;
|
||||||
|
for (int i = 0; subStr[i] != '\0'; i++) {
|
||||||
|
char c = subStr[i];
|
||||||
|
buf[0] = c;
|
||||||
|
int cw = tft.textWidth(buf, 1);
|
||||||
|
if (c == ' ') { sX += cw; continue; }
|
||||||
|
tft.setTextColor(getYapaColor(cIdx++), cardBg);
|
||||||
|
tft.drawString(buf, sX, cardY + 32, 1);
|
||||||
|
sX += cw;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
tft.setTextColor(0x8410, cardBg);
|
tft.setTextColor(0x8410, cardBg);
|
||||||
tft.drawString(subStr, cardX + 16, cardY + 32, 1);
|
tft.drawString(subStr, cardX + 16, cardY + 32, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (cardIdx == 1) {
|
} else if (cardIdx == 1) {
|
||||||
minRange = 10.0f;
|
minRange = 10.0f;
|
||||||
maxRange = 40.0f;
|
maxRange = 40.0f;
|
||||||
accentCol = isRainbowTheme() ? (uint16_t)0x07E0 : getThemeAccentColor();
|
accentCol = isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : getThemeAccentColor());
|
||||||
oldAccentCol = accentCol;
|
oldAccentCol = accentCol;
|
||||||
} else {
|
} else {
|
||||||
minRange = -10.0f;
|
minRange = -10.0f;
|
||||||
maxRange = 50.0f;
|
maxRange = 50.0f;
|
||||||
accentCol = isRainbowTheme() ? (uint16_t)0xFD20 : getThemePrimaryColor();
|
accentCol = isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(2) : getThemePrimaryColor());
|
||||||
oldAccentCol = accentCol;
|
oldAccentCol = accentCol;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Accent color changed: update vertical accent bar
|
// 1. Accent color changed: update vertical accent bar and unit "°C"
|
||||||
if (accentCol != oldAccentCol) {
|
if (accentCol != oldAccentCol) {
|
||||||
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
tft.fillRoundRect(cardX + 6, cardY + 6, 4, cardH - 12, 2, accentCol);
|
||||||
|
bool rainbowUnit = isRainbowTheme() && (accentCol != TFT_RED);
|
||||||
|
uint16_t unitCol = rainbowUnit ? getRainbowScreenColor(cardX + 268, cardY + 22) : (isYapaTheme() && accentCol != TFT_RED ? getYapaColor(3) : (accentCol == TFT_RED ? TFT_RED : 0xC618));
|
||||||
|
draw7SegDegreeC(tft, cardX + 268, cardY + 22, unitCol, cardBg, rainbowUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Horizontal Progress Gauge Bar update (only redraw when pixel fill changes or accent changes)
|
// 2. Horizontal Progress Gauge Bar update (only redraw when pixel fill changes or accent changes)
|
||||||
|
|
@ -393,9 +455,9 @@ inline void syncTriTempTrackers() {
|
||||||
float minR[3] = { 60.0f, 10.0f, -10.0f };
|
float minR[3] = { 60.0f, 10.0f, -10.0f };
|
||||||
float maxR[3] = { 120.0f, 40.0f, 50.0f };
|
float maxR[3] = { 120.0f, 40.0f, 50.0f };
|
||||||
uint16_t defAcc[3] = {
|
uint16_t defAcc[3] = {
|
||||||
isRainbowTheme() ? (uint16_t)0x07FF : getThemePrimaryColor(),
|
isRainbowTheme() ? (uint16_t)0x07FF : (isYapaTheme() ? getYapaColor(0) : getThemePrimaryColor()),
|
||||||
isRainbowTheme() ? (uint16_t)0x07E0 : getThemeAccentColor(),
|
isRainbowTheme() ? (uint16_t)0x07E0 : (isYapaTheme() ? getYapaColor(1) : getThemeAccentColor()),
|
||||||
isRainbowTheme() ? (uint16_t)0xFD20 : getThemePrimaryColor()
|
isRainbowTheme() ? (uint16_t)0xFD20 : (isYapaTheme() ? getYapaColor(2) : getThemePrimaryColor())
|
||||||
};
|
};
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
float ratio = (vals[i] - minR[i]) / (maxR[i] - minR[i]);
|
float ratio = (vals[i] - minR[i]) / (maxR[i] - minR[i]);
|
||||||
|
|
@ -430,11 +492,12 @@ inline void drawTriTempScreen(int x_offset = 0) {
|
||||||
|
|
||||||
syncTriTempTrackers();
|
syncTriTempTrackers();
|
||||||
|
|
||||||
// Draw Page Indicator: [○ ● ○ ○] (Page 2 of 4 active)
|
// Draw Page Indicator: [○ ● ○ ○ ○] (Page 2 of 5 active)
|
||||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||||
tft.fillCircle(153 + x_offset, 2, 2, getThemePrimaryColor()); // Page 2 active
|
tft.fillCircle(146 + x_offset, 2, 2, getThemePrimaryColor()); // Page 1 active
|
||||||
tft.fillCircle(167 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
tft.fillCircle(160 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
||||||
tft.fillCircle(181 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
tft.fillCircle(174 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
||||||
|
tft.fillCircle(188 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update coolant reading dynamically without redrawing entire screen
|
// Update coolant reading dynamically without redrawing entire screen
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue