diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index ff852beb69..1bced0c140 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -37,6 +37,7 @@ namespace { StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) { static constexpr uint8_t btnWidth = 115; static constexpr uint8_t btnHeight = 80; + static constexpr uint8_t lapLineHeight = 30; btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler); @@ -59,18 +60,18 @@ StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) { lv_label_set_long_mode(lapText, LV_LABEL_LONG_BREAK); lv_label_set_align(lapText, LV_LABEL_ALIGN_CENTER); lv_obj_set_width(lapText, LV_HOR_RES_MAX); - lv_obj_align(lapText, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -btnHeight); - - msecTime = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(msecTime, "00"); - lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, Colors::lightGray); - lv_obj_align(msecTime, lapText, LV_ALIGN_OUT_TOP_MID, 0, 0); + lv_obj_align(lapText, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -(btnHeight + lapLineHeight)); time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_label_set_text_static(time, "00:00"); lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, Colors::lightGray); - lv_obj_align(time, msecTime, LV_ALIGN_OUT_TOP_MID, 0, 0); + lv_obj_align(time, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10); + + msecTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(msecTime, "00"); + lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, Colors::lightGray); + lv_obj_align(msecTime, time, LV_ALIGN_IN_TOP_MID, 0, -3); SetInterfaceStopped(); @@ -135,6 +136,60 @@ void StopWatch::Start() { startTime = xTaskGetTickCount(); currentState = States::Running; wakeLock.Lock(); + + // Add first lap automatically when starting + if (lapsDone == 0) { + lapsDone = 1; + laps[0] = 0; // Current lap starts at 0 + updateLapDisplay(); + } +} + +void StopWatch::updateLapDisplay() { + std::string displayText; + displayText.reserve(maxLapCount * 20); + + std::array buffer{}; + + // Reverse loop to show newest laps first + for (int i = lapsDone - 1; i >= std::max(0, lapsDone - displayedLaps); i--) { + TimeSeparated_t times; + if (i == lapsDone - 1 && currentState == States::Running) { + // For current lap, calculate time since last lap + TickType_t currentLapTime = xTaskGetTickCount() - startTime; + if (i > 0) { + currentLapTime += oldTimeElapsed - laps[i - 1]; + } + times = convertTicksToTimeSegments(currentLapTime); + } else { + // For completed laps, show the lap duration + TickType_t lapDuration = (i == 0) ? laps[i] : laps[i] - laps[i - 1]; + times = convertTicksToTimeSegments(lapDuration); + } + + int written = (times.hours == 0) + ? snprintf(buffer.data(), + buffer.size(), + "Lap %d %2d:%02d.%02d\n", + i + 1, + times.mins, + times.secs, + times.hundredths) + : snprintf(buffer.data(), + buffer.size(), + "Lap %d %2d:%02d:%02d.%02d\n", + i + 1, + times.hours, + times.mins, + times.secs, + times.hundredths); + + if (written > 0 && written < static_cast(buffer.size())) { + displayText += buffer.data(); + } + } + + lv_label_set_text(lapText, displayText.c_str()); } void StopWatch::Pause() { @@ -163,6 +218,9 @@ void StopWatch::Refresh() { } } lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); + + // Update the lap display + updateLapDisplay(); } else if (currentState == States::Halted) { const TickType_t currentTime = xTaskGetTickCount(); if (currentTime > blinkTime) { @@ -189,22 +247,10 @@ void StopWatch::playPauseBtnEventHandler() { void StopWatch::stopLapBtnEventHandler() { // If running, then this button is used to save laps if (currentState == States::Running) { - lv_label_set_text(lapText, ""); + // Store the current lap time + laps[lapsDone-1] = oldTimeElapsed + xTaskGetTickCount() - startTime; lapsDone = std::min(lapsDone + 1, maxLapCount); - for (int i = lapsDone - displayedLaps; i < lapsDone; i++) { - if (i < 0) { - lv_label_ins_text(lapText, LV_LABEL_POS_LAST, "\n"); - continue; - } - TimeSeparated_t times = convertTicksToTimeSegments(laps[i]); - char buffer[17]; - if (times.hours == 0) { - snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d.%02d\n", i + 1, times.mins, times.secs, times.hundredths); - } else { - snprintf(buffer, sizeof(buffer), "#%2d %2d:%02d:%02d.%02d\n", i + 1, times.hours, times.mins, times.secs, times.hundredths); - } - lv_label_ins_text(lapText, LV_LABEL_POS_LAST, buffer); - } + updateLapDisplay(); } else if (currentState == States::Halted) { Reset(); } @@ -216,4 +262,4 @@ bool StopWatch::OnButtonPushed() { return true; } return false; -} +} \ No newline at end of file diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index 55a178dcbe..20478c878b 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -36,6 +36,7 @@ namespace Pinetime { bool OnButtonPushed() override; private: + void updateLapDisplay(); void SetInterfacePaused(); void SetInterfaceRunning(); void SetInterfaceStopped(); @@ -51,7 +52,7 @@ namespace Pinetime { TickType_t blinkTime = 0; static constexpr int maxLapCount = 20; TickType_t laps[maxLapCount + 1]; - static constexpr int displayedLaps = 2; + static constexpr int displayedLaps = 3; int lapsDone = 0; lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; lv_obj_t* lapText;