feat(ui): implementar renderizado identico de la pantalla de 4 cuadrantes en la transicion con iconos PID, 20 bloques en arco, degradado de fondo y badge ECO
This commit is contained in:
parent
bd62cb991d
commit
be9687c845
1 changed files with 91 additions and 17 deletions
|
|
@ -1236,9 +1236,49 @@ void plotNoData(uint8_t cell) {
|
|||
}
|
||||
}
|
||||
|
||||
// Draw parameter icon into sprite slice with true alpha channel
|
||||
inline void drawPidIconToSprite(TFT_eSprite &s, int ix, int iy, const String &pidStr, int slice_h) {
|
||||
int w = 42, h = 42;
|
||||
const unsigned short *colors = nullptr;
|
||||
const unsigned char *alphas = nullptr;
|
||||
|
||||
if (pidStr == "0105") {
|
||||
w = 38; h = 37;
|
||||
colors = icon_temp_quad; alphas = icon_temp_quad_alpha;
|
||||
} else if (pidStr == "010D") {
|
||||
w = 42; h = 42;
|
||||
colors = icon_speed_quad; alphas = icon_speed_quad_alpha;
|
||||
} else if (pidStr == "010C") {
|
||||
w = 42; h = 43;
|
||||
colors = icon_rpm_quad; alphas = icon_rpm_quad_alpha;
|
||||
} else if (pidStr == "0142" || pidStr == "ATRV") {
|
||||
w = 46; h = 35;
|
||||
colors = icon_battery_quad; alphas = icon_battery_quad_alpha;
|
||||
}
|
||||
if (!colors || !alphas) return;
|
||||
|
||||
int startJ = (iy < 0) ? -iy : 0;
|
||||
int endJ = (iy + h > slice_h) ? (slice_h - iy) : h;
|
||||
if (startJ >= endJ) return;
|
||||
|
||||
for (int j = startJ; j < endJ; j++) {
|
||||
int curY = iy + j;
|
||||
int rowOffset = j * w;
|
||||
for (int i = 0; i < w; i++) {
|
||||
int curX = ix + i;
|
||||
if (curX < 0 || curX >= 320) continue;
|
||||
uint8_t a = pgm_read_byte(&alphas[rowOffset + i]);
|
||||
if (a >= 30) {
|
||||
uint16_t fg = pgm_read_word(&colors[rowOffset + i]);
|
||||
s.drawPixel(curX, curY, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render Page 0 (4 Quadrants) into double-buffered Sprite slice
|
||||
inline void renderPage0ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int slice_h) {
|
||||
uint16_t bgCol = getThemeBgColor();
|
||||
checkUpdateThemeGradients();
|
||||
uint16_t divCol = getThemeDivColor();
|
||||
uint16_t priCol = getThemePrimaryColor();
|
||||
|
||||
|
|
@ -1250,37 +1290,71 @@ inline void renderPage0ToSprite(TFT_eSprite &s, int x_offset, int y_slice, int s
|
|||
|
||||
if (qx + 160 <= 0 || qx >= 320 || ry + 119 <= 0 || ry >= slice_h) continue;
|
||||
|
||||
s.fillRect(rx, ry, 159, 119, bgCol);
|
||||
// 1. Exact dark vignette gradient matching real arcMeter4
|
||||
s.fillRect(rx, ry, 159, 119, TFT_BLACK);
|
||||
int gradStartY = (ry < 0) ? -ry : 0;
|
||||
int gradEndY = (ry + 82 > slice_h) ? (slice_h - ry) : 82;
|
||||
for (int j = gradStartY; j < gradEndY; j++) {
|
||||
int curY = ry + j;
|
||||
if (curY >= 0 && curY < slice_h) {
|
||||
s.drawFastHLine(rx, curY, 159, themeGradQuad[j]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pidIdx = pidInCell[c];
|
||||
s.setTextColor(TFT_WHITE, bgCol);
|
||||
s.drawString(pidConfig[pidIdx][0].c_str(), qx + 8, qy + 6, 2);
|
||||
|
||||
// 2. Real high-definition parameter icon (thermometer, speedometer, tachometer, battery)
|
||||
drawPidIconToSprite(s, qx + 5, qy + 3, pidConfig[pidIdx][2], slice_h);
|
||||
|
||||
// 3. Exact 20 curved segmented gauge blocks along the arc
|
||||
int warn = warningValue[pidIdx].toInt();
|
||||
int min = pidConfig[pidIdx][4].toInt();
|
||||
int max = pidConfig[pidIdx][5].toInt();
|
||||
bool digit = pidConfig[pidIdx][7].toInt();
|
||||
float val = last_valid_data[c];
|
||||
|
||||
int barY = qy + 28;
|
||||
s.fillRoundRect(qx + 8, barY, 144, 6, 2, METER_INACTIVE_COLOR);
|
||||
if (val > -900.0f) {
|
||||
uint16_t col = getMeterColor(pidIdx, val, warn);
|
||||
float ratio = (val - (float)min) / (float)(max - min);
|
||||
if (ratio < 0.0f) ratio = 0.0f;
|
||||
if (ratio > 1.0f) ratio = 1.0f;
|
||||
int fillW = (int)(ratio * 144.0f);
|
||||
if (fillW < 4) fillW = 4;
|
||||
if (fillW > 144) fillW = 144;
|
||||
s.fillRoundRect(qx + 8, barY, fillW, 6, 2, col);
|
||||
int numActive = (val > -900.0f) ? calcMeterBlocks(val, min, max) : 0;
|
||||
uint16_t activeCol = (val > -900.0f) ? getMeterColor(pidIdx, val, warn) : priCol;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_BAR_BLOCKS; i++) {
|
||||
int bx = qx + pgm_read_word(&quadBlockMinX[i]);
|
||||
int by = qy + pgm_read_word(&quadBlockMinY[i]);
|
||||
int bw = pgm_read_word(&quadBlockMaxX[i]) - pgm_read_word(&quadBlockMinX[i]) + 1;
|
||||
int bh = pgm_read_word(&quadBlockMaxY[i]) - pgm_read_word(&quadBlockMinY[i]) + 1;
|
||||
|
||||
if (by + bh <= 0 || by >= slice_h || bx + bw <= 0 || bx >= 320) continue;
|
||||
|
||||
uint16_t bCol = (i < numActive) ? activeCol : METER_INACTIVE_COLOR;
|
||||
s.fillRoundRect(bx, by, bw, bh, 2, bCol);
|
||||
}
|
||||
|
||||
// 4. Digital value string
|
||||
String numStr = (val <= -900.0f) ? "---" : String(val, digit);
|
||||
s.setTextColor(priCol, bgCol);
|
||||
s.setTextColor(priCol);
|
||||
s.drawRightString(numStr.c_str(), qx + 152, qy + 74, 4);
|
||||
}
|
||||
|
||||
// Crosshair dividers
|
||||
// 5. Eco Badge if active
|
||||
if (isEcoOptimal) {
|
||||
int rpmCell = 2;
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (pidConfig[pidInCell[c]][3].toInt() == 3) {
|
||||
rpmCell = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int bx = cell4_x[rpmCell] + 100 + x_offset;
|
||||
int by = cell4_y[rpmCell] + 4 - y_slice;
|
||||
int bw = 48, bh = 18;
|
||||
if (by + bh > 0 && by < slice_h && bx + bw > 0 && bx < 320) {
|
||||
s.fillRoundRect(bx, by, bw, bh, 4, 0x0202);
|
||||
s.drawRoundRect(bx, by, bw, bh, 4, 0x07E0);
|
||||
s.setTextColor(TFT_WHITE, 0x0202);
|
||||
s.drawCentreString("ECO", bx + (bw / 2), by + 1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Crosshair dividers
|
||||
s.fillRect(159 + x_offset, 0, 2, slice_h, divCol);
|
||||
int hLineY = 119 - y_slice;
|
||||
if (hLineY >= 0 && hLineY < slice_h) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue