diff --git a/sketch/obd2_gauge/meter.h b/sketch/obd2_gauge/meter.h index 578e32c..9275dcd 100644 --- a/sketch/obd2_gauge/meter.h +++ b/sketch/obd2_gauge/meter.h @@ -1236,6 +1236,126 @@ void plotNoData(uint8_t cell) { } } +// Fast slide-frame rendering of Page 0 (4 Quadrants) shifted by x_offset +inline void drawSlidePage0(int x_offset) { + tft.fillRect(x_offset, 0, 320, 240, TFT_BLACK); + + // 4 Quadrants + for (uint8_t c = 0; c < 4; c++) { + int qx = cell4_x[c] + x_offset; + int qy = cell4_y[c]; + int rx = (c & 1) ? (161 + x_offset) : (0 + x_offset); + int ry = (c & 2) ? 121 : 0; + + // Ambient vignette gradient + tft.fillRectVGradient(rx, ry, 159, 82, getThemeBgColor(), TFT_BLACK); + tft.fillRect(rx, ry + 82, 159, 37, TFT_BLACK); + + // Header PID icon + uint8_t pidIdx = pidInCell[c]; + drawPidIcon(qx + 5, qy + 3, pidConfig[pidIdx][2]); + + 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]; + + // Horizontal gauge bar + int barY = qy + 32; + tft.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; + tft.fillRoundRect(qx + 8, barY, fillW, 6, 2, col); + } + + // Digital value using DSEG7 Modern 34pt + String numStr = (val <= -900.0f) ? "---" : String(val, digit); + tft.loadFont(DSEG7_Modern_BoldItalic_34); + tft.setTextColor(getThemePrimaryColor(), TFT_BLACK); + tft.setTextPadding(114); + tft.drawRightString(numStr.c_str(), qx + 152, qy + 74, 1); + tft.setTextPadding(0); + tft.unloadFont(); + } + + // Crosshair dividers + uint16_t divCol = getThemeDivColor(); + tft.fillRect(159 + x_offset, 0, 2, 240, divCol); + tft.fillRect(x_offset, 119, 320, 2, divCol); +} + +// True physical mobile-like slide transition: both screens visibly move across the glass +inline void animateSlideTransition(bool swipeLeft) { + touchBeep(); + const uint8_t FRAMES = 6; + const int16_t step_shifts[FRAMES] = { 54, 108, 162, 216, 270, 320 }; + + if (swipeLeft) { + // SWIPE LEFT: Page 0 slides out to the left, Page 1 enters from the right + for (uint8_t f = 0; f < FRAMES; f++) { + int16_t shift = step_shifts[f]; + int16_t splitX = 320 - shift; + + if (splitX > 0) { + tft.setViewport(0, 0, splitX, 240, false); + drawSlidePage0(-shift); + } + + if (splitX < 320) { + tft.setViewport(splitX, 0, 320 - splitX, 240, false); + drawSlidePage1(splitX); + } + + tft.resetViewport(); + if (splitX > 0 && splitX < 320) { + tft.drawFastVLine(splitX, 0, 240, getThemePrimaryColor()); + tft.drawFastVLine(splitX + 1, 0, 240, TFT_WHITE); + } + + tft.fillCircle(153, 2, 2, (splitX > 160) ? getThemePrimaryColor() : 0x5AEB); + tft.fillCircle(167, 2, 2, (splitX <= 160) ? getThemePrimaryColor() : 0x5AEB); + + delay(12); + } + } else { + // SWIPE RIGHT: Page 1 slides out to the right, Page 0 enters from the left + for (uint8_t f = 0; f < FRAMES; f++) { + int16_t shift = step_shifts[f]; + int16_t splitX = shift; + + if (splitX > 0) { + tft.setViewport(0, 0, splitX, 240, false); + drawSlidePage0(splitX - 320); + } + + if (splitX < 320) { + tft.setViewport(splitX, 0, 320 - splitX, 240, false); + drawSlidePage1(splitX); + } + + tft.resetViewport(); + if (splitX > 0 && splitX < 320) { + tft.drawFastVLine(splitX, 0, 240, getThemePrimaryColor()); + tft.drawFastVLine(splitX - 1, 0, 240, TFT_WHITE); + } + + tft.fillCircle(153, 2, 2, (splitX >= 160) ? getThemePrimaryColor() : 0x5AEB); + tft.fillCircle(167, 2, 2, (splitX < 160) ? getThemePrimaryColor() : 0x5AEB); + + delay(12); + } + } + + tft.resetViewport(); +} + /*-------------------*/ // initialize display void initScreen() { diff --git a/sketch/obd2_gauge/tri_temp.h b/sketch/obd2_gauge/tri_temp.h index 2cbb7d8..5902505 100644 --- a/sketch/obd2_gauge/tri_temp.h +++ b/sketch/obd2_gauge/tri_temp.h @@ -220,30 +220,11 @@ inline void updateTriTempSensors(bool forceRedraw = false) { } } -// Animated mobile-like slide transition between screens -inline void animateSlideTransition(bool swipeLeft) { - touchBeep(); - const uint8_t STEPS = 10; - const uint16_t STEP_W = 320 / STEPS; // 32 px - uint16_t primary = getThemePrimaryColor(); - - if (swipeLeft) { - // Swipe left: wipe beam sweeping from right to left - for (int s = 0; s < STEPS; s++) { - int x = 320 - (s + 1) * STEP_W; - tft.fillRect(x, 0, STEP_W, 240, TFT_BLACK); - tft.drawFastVLine(x, 0, 240, primary); - tft.drawFastVLine(x + 1, 0, 240, TFT_WHITE); - delay(10); - } - } else { - // Swipe right: wipe beam sweeping from left to right - for (int s = 0; s < STEPS; s++) { - int x = s * STEP_W; - tft.fillRect(x, 0, STEP_W, 240, TFT_BLACK); - tft.drawFastVLine(x + STEP_W - 1, 0, 240, primary); - tft.drawFastVLine(x + STEP_W - 2, 0, 240, TFT_WHITE); - delay(10); - } - } +// Draw fast slide frame of Page 1 (3 temperature cards) shifted by x_offset +inline void drawSlidePage1(int x_offset) { + tft.fillRect(x_offset, 0, 320, 240, TFT_BLACK); + drawTriTempCard(0, tempEngineCoolant, x_offset); + drawTriTempCard(1, tempInterior, x_offset); + drawTriTempCard(2, tempExterior, x_offset); } +