feat(ui): pantalla de instrumental deportivo con tacometro, velocidad, refrigerante y bateria
- Agrega cluster_screen.h con diseno estilo cockpit (Pantalla 4). - Tacometro horizontal deportivo (RPM) con 12 segmentos de color dinamico y lectura digital. - Velocimetro digital gigante en tipografia DSEG7 44pt con etiqueta de origen GPS/OBD y riel luminico. - Relojes inferiores dobles para Temperatura de Refrigerante (°C) y Voltaje de Bateria (V). - Expansion del sistema de navegacion y paginacion a 5 pantallas (0 a 4) con indicadores sincronizados. - Integracion completa con transiciones suaves y soporte para los 9 temas de color.
This commit is contained in:
parent
f6caf547fe
commit
d614ea633a
8 changed files with 571 additions and 47 deletions
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
#include <pgmspace.h>
|
||||
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, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2479,14 +2479,16 @@ void transitionMenu() {
|
|||
// 2. Touch on [ PROBAR EFECTO ] (y: 142 to 176)
|
||||
else if (ty >= 142 && ty <= 176 && tx >= 40 && tx <= 280) {
|
||||
touchBeep();
|
||||
// Demonstrate transition across all 4 pages (Page 0 -> Page 1 -> Page 2 -> Page 3 -> Page 0)
|
||||
// Demonstrate transition across all 5 pages (Page 0 -> Page 1 -> Page 2 -> Page 3 -> Page 4 -> Page 0)
|
||||
performScreenTransition(true, 0, 1);
|
||||
delay(350);
|
||||
performScreenTransition(true, 1, 2);
|
||||
delay(350);
|
||||
performScreenTransition(true, 2, 3);
|
||||
delay(350);
|
||||
performScreenTransition(false, 3, 0);
|
||||
performScreenTransition(true, 3, 4);
|
||||
delay(350);
|
||||
performScreenTransition(false, 4, 0);
|
||||
delay(250);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
drawTransitionUI();
|
||||
|
|
|
|||
|
|
@ -348,12 +348,12 @@ inline void drawGpsClockScreen(int x_offset = 0) {
|
|||
uint16_t cardBorder = 0x2945; // Subtle edge border
|
||||
bool synced = isGpsSynced();
|
||||
|
||||
// 1. TOP BAR (y = 0 to 18)
|
||||
// Center: 4 Pagination Indicator Dots [○ ○ ● ○] (Page 3 active)
|
||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||
tft.fillCircle(153 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
||||
tft.fillCircle(167 + x_offset, 2, 2, priCol); // Page 3 active
|
||||
tft.fillCircle(181 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
||||
// Center: 5 Pagination Indicator Dots [○ ○ ● ○ ○] (Page 2 of 5 active)
|
||||
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||
tft.fillCircle(146 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||
tft.fillCircle(160 + x_offset, 2, 2, priCol); // Page 2 active
|
||||
tft.fillCircle(174 + x_offset, 2, 2, 0x5AEB); // Page 3 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)
|
||||
int clkX = 4 + x_offset;
|
||||
|
|
|
|||
|
|
@ -103,12 +103,12 @@ inline void drawGpsNavScreen(int x_offset = 0) {
|
|||
uint16_t cardBorder = 0x2945; // Subtle edge border
|
||||
bool synced = isGpsSynced();
|
||||
|
||||
// 1. TOP BAR (y = 0 to 18)
|
||||
// Center: 4 Pagination Indicator Dots [○ ○ ○ ●] (Page 4 active)
|
||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||
tft.fillCircle(153 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
||||
tft.fillCircle(167 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
||||
tft.fillCircle(181 + x_offset, 2, 2, priCol); // Page 4 active
|
||||
// Center: 5 Pagination Indicator Dots [○ ○ ○ ● ○] (Page 3 of 5 active)
|
||||
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||
tft.fillCircle(146 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||
tft.fillCircle(160 + x_offset, 2, 2, 0x5AEB); // Page 2 inactive
|
||||
tft.fillCircle(174 + x_offset, 2, 2, priCol); // Page 3 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)
|
||||
int c0X = 4 + x_offset;
|
||||
|
|
|
|||
|
|
@ -1844,19 +1844,23 @@ inline void animateBlackTransition(int8_t toPage = -1) {
|
|||
renderPage1ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else if (toPage == 2)
|
||||
renderPage2ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else
|
||||
else if (toPage == 3)
|
||||
renderPage3ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else
|
||||
renderPage4ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
|
||||
// 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) {
|
||||
sprTrans.fillCircle(139, 2, 2,
|
||||
sprTrans.fillCircle(132, 2, 2,
|
||||
(toPage == 0) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(153, 2, 2,
|
||||
sprTrans.fillCircle(146, 2, 2,
|
||||
(toPage == 1) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(167, 2, 2,
|
||||
sprTrans.fillCircle(160, 2, 2,
|
||||
(toPage == 2) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(181, 2, 2,
|
||||
sprTrans.fillCircle(174, 2, 2,
|
||||
(toPage == 3) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(188, 2, 2,
|
||||
(toPage == 4) ? getThemePrimaryColor() : 0x5AEB);
|
||||
}
|
||||
|
||||
sprTrans.pushSprite(0, y_slice);
|
||||
|
|
@ -1916,8 +1920,10 @@ inline void animateFadeTransition(int8_t fromPage = -1, int8_t toPage = -1) {
|
|||
renderPage1ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else if (fromPage == 2)
|
||||
renderPage2ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else
|
||||
else if (fromPage == 3)
|
||||
renderPage3ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
else
|
||||
renderPage4ToSprite(sprTrans, 0, y_slice, slice_h);
|
||||
|
||||
if (toPage == 0)
|
||||
renderPage0ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||
|
|
@ -1925,8 +1931,10 @@ inline void animateFadeTransition(int8_t fromPage = -1, int8_t toPage = -1) {
|
|||
renderPage1ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||
else if (toPage == 2)
|
||||
renderPage2ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||
else
|
||||
else if (toPage == 3)
|
||||
renderPage3ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||
else
|
||||
renderPage4ToSprite(sprFadeB, 0, y_slice, slice_h);
|
||||
|
||||
uint16_t *pA = (uint16_t *)sprTrans.getPointer();
|
||||
uint16_t *pB = (uint16_t *)sprFadeB.getPointer();
|
||||
|
|
@ -1956,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) {
|
||||
uint8_t activeDot = (alpha < 16) ? fromPage : toPage;
|
||||
sprTrans.fillCircle(139, 2, 2,
|
||||
sprTrans.fillCircle(132, 2, 2,
|
||||
(activeDot == 0) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(153, 2, 2,
|
||||
sprTrans.fillCircle(146, 2, 2,
|
||||
(activeDot == 1) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(167, 2, 2,
|
||||
sprTrans.fillCircle(160, 2, 2,
|
||||
(activeDot == 2) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(181, 2, 2,
|
||||
sprTrans.fillCircle(174, 2, 2,
|
||||
(activeDot == 3) ? getThemePrimaryColor() : 0x5AEB);
|
||||
sprTrans.fillCircle(188, 2, 2,
|
||||
(activeDot == 4) ? getThemePrimaryColor() : 0x5AEB);
|
||||
}
|
||||
|
||||
sprTrans.pushSprite(0, y_slice);
|
||||
|
|
@ -1987,7 +1997,7 @@ inline void performScreenTransition(bool swipeLeft, int8_t fromPage = -1,
|
|||
if (fromPage < 0)
|
||||
fromPage = currentScreenPage;
|
||||
if (toPage < 0)
|
||||
toPage = (fromPage + 1) % 4;
|
||||
toPage = (fromPage + 1) % 5;
|
||||
if (transitionType == 1) {
|
||||
animateFadeTransition(fromPage, toPage);
|
||||
} else {
|
||||
|
|
@ -2026,6 +2036,8 @@ void initScreen(bool redrawTFT) {
|
|||
syncGpsClockTrackers();
|
||||
} else if (currentScreenPage == 3) {
|
||||
syncGpsNavTrackers();
|
||||
} else if (currentScreenPage == 4) {
|
||||
syncClusterTrackers();
|
||||
} else if (currentScreenPage == 0 && fullScreenCell == -1) {
|
||||
syncPage0Trackers();
|
||||
}
|
||||
|
|
@ -2060,6 +2072,11 @@ void initScreen(bool redrawTFT) {
|
|||
Serial.println(">>> [DB] initScreen: drawing drawGpsNavScreen(0)");
|
||||
#endif
|
||||
drawGpsNavScreen(0);
|
||||
} else if (currentScreenPage == 4) {
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println(">>> [DB] initScreen: drawing drawClusterScreen(0)");
|
||||
#endif
|
||||
drawClusterScreen(0);
|
||||
} else {
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println(">>> [DB] initScreen: drawing Page 0 quadrants");
|
||||
|
|
@ -2070,11 +2087,12 @@ void initScreen(bool redrawTFT) {
|
|||
arcMeter4(c, pid);
|
||||
}
|
||||
drawQuadrantDividers();
|
||||
// Pagination indicator dots [● ○ ○ ○] (Page 1 active)
|
||||
tft.fillCircle(139, 2, 2, getThemePrimaryColor()); // Page 1 active
|
||||
tft.fillCircle(153, 2, 2, 0x5AEB); // Page 2 inactive
|
||||
tft.fillCircle(167, 2, 2, 0x5AEB); // Page 3 inactive
|
||||
tft.fillCircle(181, 2, 2, 0x5AEB); // Page 4 inactive
|
||||
// Pagination indicator dots [● ○ ○ ○ ○] (Page 0 active)
|
||||
tft.fillCircle(132, 2, 2, getThemePrimaryColor());
|
||||
tft.fillCircle(146, 2, 2, 0x5AEB);
|
||||
tft.fillCircle(160, 2, 2, 0x5AEB);
|
||||
tft.fillCircle(174, 2, 2, 0x5AEB);
|
||||
tft.fillCircle(188, 2, 2, 0x5AEB);
|
||||
}
|
||||
if (currentScreenPage == 0 && fullScreenCell == -1) {
|
||||
badgeEcoDrawn = false;
|
||||
|
|
@ -2408,6 +2426,8 @@ void updateMeter(uint8_t pidNo, String response) { // update parameter on screen
|
|||
}
|
||||
} else if (currentScreenPage == 0) {
|
||||
plotArc4(pidNo, data, warn, min, max, digit, unit);
|
||||
} else if (currentScreenPage == 4) {
|
||||
updateClusterScreen(false);
|
||||
}
|
||||
bt_message = ""; // reset
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,8 +301,8 @@ int8_t currentScreenPage =
|
|||
inline void setScreenPage(int8_t page) {
|
||||
if (page < 0)
|
||||
page = 0;
|
||||
if (page > 3)
|
||||
page = 3;
|
||||
if (page > 4)
|
||||
page = 4;
|
||||
currentScreenPage = page;
|
||||
pref.begin("setting", false);
|
||||
pref.putChar("scr_page", page);
|
||||
|
|
@ -488,6 +488,7 @@ String sendATCommand(const String &cmd, uint32_t timeoutMs = 2000) {
|
|||
#include "gps_module.h"
|
||||
#include "gps_clock.h"
|
||||
#include "gps_nav.h"
|
||||
#include "cluster_screen.h"
|
||||
#include "meter.h"
|
||||
#include "config.h"
|
||||
|
||||
|
|
@ -710,7 +711,7 @@ recent_client_addr : {0x00,0x00,0x00,0x00,0x00,0x00} array of bytes[6]
|
|||
if (transitionType > 1)
|
||||
transitionType = 0;
|
||||
currentScreenPage = pref.getChar("scr_page", 0);
|
||||
if (currentScreenPage < 0 || currentScreenPage > 3)
|
||||
if (currentScreenPage < 0 || currentScreenPage > 4)
|
||||
currentScreenPage = 0;
|
||||
if (brightnessIndex > 0) {
|
||||
targetBacklight = BRIGHTNESS_PWM_TABLE[brightnessIndex];
|
||||
|
|
@ -862,6 +863,11 @@ void loop() {
|
|||
updateGpsNavScreen(false);
|
||||
}
|
||||
|
||||
// Non-blocking live refresh for resting Page 4 (Cockpit Instrumental Deportivo)
|
||||
if (currentScreenPage == 4 && fullScreenCell == -1) {
|
||||
updateClusterScreen(false);
|
||||
}
|
||||
|
||||
if (wokeFromSleep) {
|
||||
wokeFromSleep = false;
|
||||
lastActivityTime = millis();
|
||||
|
|
@ -921,10 +927,10 @@ void loop() {
|
|||
// (disabled in full-screen mode)
|
||||
if (!longPressHandled) {
|
||||
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;
|
||||
touchBeep();
|
||||
uint8_t nextPage = (currentScreenPage + 1) % 4;
|
||||
uint8_t nextPage = (currentScreenPage + 1) % 5;
|
||||
performScreenTransition(true, currentScreenPage, nextPage);
|
||||
setScreenPage(nextPage);
|
||||
initScreen(false); // Seamless: keep transition frame without blanking
|
||||
|
|
@ -934,11 +940,11 @@ void loop() {
|
|||
lastActivityTime = millis();
|
||||
} else if (fullScreenCell == -1 && liveDeltaX > 28 &&
|
||||
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;
|
||||
touchBeep();
|
||||
uint8_t nextPage =
|
||||
(currentScreenPage == 0) ? 3 : (currentScreenPage - 1);
|
||||
(currentScreenPage == 0) ? 4 : (currentScreenPage - 1);
|
||||
performScreenTransition(false, currentScreenPage, nextPage);
|
||||
setScreenPage(nextPage);
|
||||
initScreen(false); // Seamless: keep transition frame without blanking
|
||||
|
|
@ -978,7 +984,7 @@ void loop() {
|
|||
// SWIPE LEFT
|
||||
longPressHandled = true;
|
||||
touchBeep();
|
||||
uint8_t nextPage = (currentScreenPage + 1) % 4;
|
||||
uint8_t nextPage = (currentScreenPage + 1) % 5;
|
||||
performScreenTransition(true, currentScreenPage, nextPage);
|
||||
setScreenPage(nextPage);
|
||||
initScreen(false); // Seamless: keep transition frame without blanking
|
||||
|
|
@ -991,7 +997,7 @@ void loop() {
|
|||
longPressHandled = true;
|
||||
touchBeep();
|
||||
uint8_t nextPage =
|
||||
(currentScreenPage == 0) ? 3 : (currentScreenPage - 1);
|
||||
(currentScreenPage == 0) ? 4 : (currentScreenPage - 1);
|
||||
performScreenTransition(false, currentScreenPage, nextPage);
|
||||
setScreenPage(nextPage);
|
||||
initScreen(false); // Seamless: keep transition frame without blanking
|
||||
|
|
@ -1023,6 +1029,9 @@ void loop() {
|
|||
} else if (currentScreenPage == 3) {
|
||||
// Tap on GPS Navigation screen: immediate telemetry refresh
|
||||
updateGpsNavScreen(true);
|
||||
} else if (currentScreenPage == 4) {
|
||||
// Tap on Cockpit Instrumental: immediate cluster refresh
|
||||
updateClusterScreen(true);
|
||||
}
|
||||
waitForTouchRelease();
|
||||
lastActivityTime = millis();
|
||||
|
|
|
|||
|
|
@ -492,11 +492,12 @@ inline void drawTriTempScreen(int x_offset = 0) {
|
|||
|
||||
syncTriTempTrackers();
|
||||
|
||||
// Draw Page Indicator: [○ ● ○ ○] (Page 2 of 4 active)
|
||||
tft.fillCircle(139 + x_offset, 2, 2, 0x5AEB); // Page 1 inactive
|
||||
tft.fillCircle(153 + x_offset, 2, 2, getThemePrimaryColor()); // Page 2 active
|
||||
tft.fillCircle(167 + x_offset, 2, 2, 0x5AEB); // Page 3 inactive
|
||||
tft.fillCircle(181 + x_offset, 2, 2, 0x5AEB); // Page 4 inactive
|
||||
// Draw Page Indicator: [○ ● ○ ○ ○] (Page 2 of 5 active)
|
||||
tft.fillCircle(132 + x_offset, 2, 2, 0x5AEB); // Page 0 inactive
|
||||
tft.fillCircle(146 + x_offset, 2, 2, getThemePrimaryColor()); // Page 1 active
|
||||
tft.fillCircle(160 + x_offset, 2, 2, 0x5AEB); // Page 2 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
|
||||
|
|
|
|||
Loading…
Reference in a new issue