diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index d4a73f5e..49a56a07 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -414,6 +414,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) break; case Apps::Metronome: currentScreen = std::make_unique(this, motorController, *systemTask); + ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::Motion: currentScreen = std::make_unique(this, motionController); diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index 7bfbccb7..ce23cc3e 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -1,35 +1,15 @@ #include "Metronome.h" - -#include "Screen.h" #include "Symbols.h" -#include "lvgl/lvgl.h" -#include "FreeRTOSConfig.h" -#include "task.h" - -#include -#include using namespace Pinetime::Applications::Screens; namespace { - float calculateDelta(const TickType_t startTime, const TickType_t currentTime) { - TickType_t delta = 0; - // Take care of overflow - if (startTime > currentTime) { - delta = 0xffffffff - startTime; - delta += (currentTime + 1); - } else { - delta = currentTime - startTime; - } - return static_cast(delta) / static_cast(configTICK_RATE_HZ); - } - - static void eventHandler(lv_obj_t* obj, lv_event_t event) { - Metronome* screen = static_cast(obj->user_data); + void eventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); screen->OnEvent(obj, event); } - lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x = 0, uint8_t y = 0) { + lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x, uint8_t y) { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font); lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); @@ -41,7 +21,7 @@ namespace { } Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask) - : Screen(app), running {true}, currentState {States::Stopped}, startTime {}, motorController {motorController}, systemTask {systemTask} { + : Screen(app), motorController {motorController}, systemTask {systemTask} { bpmArc = lv_arc_create(lv_scr_act(), nullptr); bpmArc->user_data = this; @@ -52,10 +32,10 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl lv_arc_set_value(bpmArc, bpm); lv_obj_set_size(bpmArc, 210, 210); lv_arc_set_adjustable(bpmArc, true); - lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 7); + lv_obj_align(bpmArc, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); - bpmValue = createLabel(std::to_string(lv_arc_get_value(bpmArc)).c_str(), bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55); - bpmLegend = createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0); + bpmValue = createLabel("120", bpmArc, LV_ALIGN_IN_TOP_MID, &jetbrains_mono_76, 0, 55); + createLabel("bpm", bpmValue, LV_ALIGN_OUT_BOTTOM_MID, &jetbrains_mono_bold_20, 0, 0); bpmTap = lv_btn_create(lv_scr_act(), nullptr); bpmTap->user_data = this; @@ -69,20 +49,23 @@ Metronome::Metronome(DisplayApp* app, Controllers::MotorController& motorControl lv_obj_set_event_cb(bpbDropdown, eventHandler); lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_MAIN, LV_STATE_DEFAULT, 20); lv_obj_set_style_local_pad_left(bpbDropdown, LV_DROPDOWN_PART_LIST, LV_STATE_DEFAULT, 20); - lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 15, -4); + lv_obj_set_size(bpbDropdown, 115, 50); + lv_obj_align(bpbDropdown, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_dropdown_set_options(bpbDropdown, "1\n2\n3\n4\n5\n6\n7\n8\n9"); lv_dropdown_set_selected(bpbDropdown, bpb - 1); - bpbLegend = lv_label_create(bpbDropdown, nullptr); - lv_label_set_text(bpbLegend, "bpb"); - lv_obj_align(bpbLegend, bpbDropdown, LV_ALIGN_IN_RIGHT_MID, -15, 0); + lv_dropdown_set_show_selected(bpbDropdown, false); + lv_dropdown_set_text(bpbDropdown, ""); + + currentBpbText = lv_label_create(bpbDropdown, nullptr); + lv_label_set_text_fmt(currentBpbText, "%d bpb", bpb); + lv_obj_align(currentBpbText, bpbDropdown, LV_ALIGN_CENTER, 0, 0); playPause = lv_btn_create(lv_scr_act(), nullptr); playPause->user_data = this; lv_obj_set_event_cb(playPause, eventHandler); - lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10); - lv_obj_set_height(playPause, 39); - playPauseLabel = lv_label_create(playPause, nullptr); - lv_label_set_text(playPauseLabel, Symbols::play); + lv_obj_set_size(playPause, 115, 50); + lv_obj_align(playPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play); app->SetTouchMode(DisplayApp::TouchModes::Polling); } @@ -93,28 +76,17 @@ Metronome::~Metronome() { lv_obj_clean(lv_scr_act()); } -bool Metronome::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - return true; -} - bool Metronome::Refresh() { - switch (currentState) { - case States::Stopped: { - break; - } - case States::Running: { - if (calculateDelta(startTime, xTaskGetTickCount()) >= (60.0 / bpm)) { - counter--; - startTime -= 60.0 / bpm; - startTime = xTaskGetTickCount(); - if (counter == 0) { - counter = bpb; - motorController.SetDuration(90); - } else { - motorController.SetDuration(30); - } + if (metronomeStarted) { + if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) { + startTime += 60 * configTICK_RATE_HZ / bpm; + counter--; + if (counter == 0) { + counter = bpb; + motorController.SetDuration(90); + } else { + motorController.SetDuration(30); } - break; } } return running; @@ -128,42 +100,39 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) { lv_label_set_text_fmt(bpmValue, "%03d", bpm); } else if (obj == bpbDropdown) { bpb = lv_dropdown_get_selected(obj) + 1; + lv_label_set_text_fmt(currentBpbText, "%d bpb", bpb); + lv_obj_realign(currentBpbText); } break; } case LV_EVENT_PRESSED: { if (obj == bpmTap) { - float timeDelta = calculateDelta(tappedTime, xTaskGetTickCount()); - if (tappedTime == 0 || timeDelta > 3) { - tappedTime = xTaskGetTickCount(); - } else { - bpm = ceil(60.0 / timeDelta); + TickType_t delta = xTaskGetTickCount() - tappedTime; + if (tappedTime != 0 && delta < configTICK_RATE_HZ * 3) { + bpm = configTICK_RATE_HZ * 60 / delta; lv_arc_set_value(bpmArc, bpm); lv_label_set_text_fmt(bpmValue, "%03d", bpm); - tappedTime = xTaskGetTickCount(); } + tappedTime = xTaskGetTickCount(); } break; } case LV_EVENT_CLICKED: { if (obj == playPause) { - currentState = (currentState == States::Stopped ? States::Running : States::Stopped); - switch (currentState) { - case States::Stopped: { - lv_label_set_text(playPauseLabel, Symbols::play); - systemTask.PushMessage(System::Messages::EnableSleeping); - break; - } - case States::Running: { - lv_label_set_text(playPauseLabel, Symbols::pause); - systemTask.PushMessage(System::Messages::DisableSleeping); - startTime = xTaskGetTickCount(); - counter = 1; - break; - } + metronomeStarted = !metronomeStarted; + if (metronomeStarted) { + lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::pause); + systemTask.PushMessage(System::Messages::DisableSleeping); + startTime = xTaskGetTickCount(); + counter = 1; + } else { + lv_obj_set_style_local_value_str(playPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Symbols::play); + systemTask.PushMessage(System::Messages::EnableSleeping); } } break; } + default: + break; } } diff --git a/src/displayapp/screens/Metronome.h b/src/displayapp/screens/Metronome.h index 3a1f1084..a4baa096 100644 --- a/src/displayapp/screens/Metronome.h +++ b/src/displayapp/screens/Metronome.h @@ -3,32 +3,32 @@ #include "systemtask/SystemTask.h" #include "components/motor/MotorController.h" -#include +namespace Pinetime { + namespace Applications { + namespace Screens { -namespace Pinetime::Applications::Screens { + class Metronome : public Screen { + public: + Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask); + ~Metronome() override; + bool Refresh() override; + void OnEvent(lv_obj_t* obj, lv_event_t event); - class Metronome : public Screen { - public: - Metronome(DisplayApp* app, Controllers::MotorController& motorController, System::SystemTask& systemTask); - ~Metronome() override; - bool Refresh() override; - bool OnTouchEvent(TouchEvents event) override; - void OnEvent(lv_obj_t* obj, lv_event_t event); - enum class States { Running, Stopped }; + private: + TickType_t startTime = 0; + TickType_t tappedTime = 0; + Controllers::MotorController& motorController; + System::SystemTask& systemTask; + int16_t bpm = 120; + uint8_t bpb = 4; + uint8_t counter = 1; - private: - bool running; - States currentState; - TickType_t startTime; - TickType_t tappedTime = 0; - Controllers::MotorController& motorController; - System::SystemTask& systemTask; - uint16_t bpm = 120; - uint8_t bpb = 4; - uint8_t counter = 1; + bool metronomeStarted = false; - lv_obj_t *bpmArc, *bpmTap, *bpmValue, *bpmLegend; - lv_obj_t *bpbDropdown, *bpbLegend; - lv_obj_t *playPause, *playPauseLabel; - }; + lv_obj_t *bpmArc, *bpmTap, *bpmValue; + lv_obj_t *bpbDropdown, *currentBpbText; + lv_obj_t *playPause; + }; + } + } }