diff --git a/src/StaticStack.h b/src/StaticStack.h new file mode 100644 index 00000000..64886604 --- /dev/null +++ b/src/StaticStack.h @@ -0,0 +1,38 @@ +#include +#include + +template class StaticStack { +public: + T Pop(); + void Push(T element); + void Reset(); + T Top(); + +private: + std::array elementArray; + // Number of elements in stack, points to the next empty slot + size_t stackPointer = 0; +}; + +// Returns random data when popping from empty array. +template T StaticStack::Pop() { + if (stackPointer > 0) { + stackPointer--; + } + return elementArray[stackPointer]; +} + +template void StaticStack::Push(T element) { + if (stackPointer < elementArray.size()) { + elementArray[stackPointer] = element; + stackPointer++; + } +} + +template void StaticStack::Reset() { + stackPointer = 0; +} + +template T StaticStack::Top() { + return elementArray[stackPointer - 1]; +} diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 9535c2f3..74af01b3 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -102,9 +102,9 @@ void DisplayApp::Start(System::BootErrors error) { bootError = error; if (error == System::BootErrors::TouchController) { - LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); } if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) { @@ -132,7 +132,25 @@ void DisplayApp::InitHw() { void DisplayApp::Refresh() { auto LoadPreviousScreen = [this]() { - LoadApp(returnToApp, returnDirection); + FullRefreshDirections returnDirection; + switch (appStackDirections.Pop()) { + case FullRefreshDirections::Up: + returnDirection = FullRefreshDirections::Down; + break; + case FullRefreshDirections::Down: + returnDirection = FullRefreshDirections::Up; + break; + case FullRefreshDirections::LeftAnim: + returnDirection = FullRefreshDirections::RightAnim; + break; + case FullRefreshDirections::RightAnim: + returnDirection = FullRefreshDirections::LeftAnim; + break; + default: + returnDirection = FullRefreshDirections::None; + break; + } + LoadScreen(returnAppStack.Pop(), returnDirection); }; TickType_t queueTimeout; @@ -180,14 +198,14 @@ void DisplayApp::Refresh() { // Screens::Clock::BleConnectionStates::NotConnected); break; case Messages::NewNotification: - LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; case Messages::TimerDone: if (currentApp == Apps::Timer) { auto* timer = static_cast(currentScreen.get()); timer->Reset(); } else { - LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } break; case Messages::AlarmTriggered: @@ -195,11 +213,11 @@ void DisplayApp::Refresh() { auto* alarm = static_cast(currentScreen.get()); alarm->SetAlerting(); } else { - LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Alarm, DisplayApp::FullRefreshDirections::None); } break; case Messages::ShowPairingKey: - LoadApp(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); break; case Messages::TouchEvent: { if (state != States::Running) { @@ -209,17 +227,30 @@ void DisplayApp::Refresh() { if (gesture == TouchEvents::None) { break; } + auto LoadDirToReturnSwipe = [](DisplayApp::FullRefreshDirections refreshDirection) { + switch (refreshDirection) { + default: + case DisplayApp::FullRefreshDirections::Up: + return TouchEvents::SwipeDown; + case DisplayApp::FullRefreshDirections::Down: + return TouchEvents::SwipeUp; + case DisplayApp::FullRefreshDirections::LeftAnim: + return TouchEvents::SwipeRight; + case DisplayApp::FullRefreshDirections::RightAnim: + return TouchEvents::SwipeLeft; + } + }; if (!currentScreen->OnTouchEvent(gesture)) { if (currentApp == Apps::Clock) { switch (gesture) { case TouchEvents::SwipeUp: - LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); break; case TouchEvents::SwipeDown: - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); break; case TouchEvents::SwipeRight: - LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); + LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); break; case TouchEvents::DoubleTap: PushMessageToSystemTask(System::Messages::GoToSleep); @@ -227,7 +258,7 @@ void DisplayApp::Refresh() { default: break; } - } else if (returnTouchEvent == gesture) { + } else if (gesture == LoadDirToReturnSwipe(appStackDirections.Top())) { LoadPreviousScreen(); } } else { @@ -246,26 +277,28 @@ void DisplayApp::Refresh() { case Messages::ButtonLongPressed: if (currentApp != Apps::Clock) { if (currentApp == Apps::Notifications) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Up); } else if (currentApp == Apps::QuickSettings) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Down); } + appStackDirections.Reset(); + returnAppStack.Reset(); } break; case Messages::ButtonLongerPressed: // Create reboot app and open it instead - LoadApp(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); break; case Messages::ButtonDoubleClicked: if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) { - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); } break; case Messages::BleFirmwareUpdateStarted: - LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); break; case Messages::BleRadioEnableToggle: PushMessageToSystemTask(System::Messages::BleRadioEnableToggle); @@ -275,7 +308,7 @@ void DisplayApp::Refresh() { // What should happen here? break; case Messages::Clock: - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); break; } } @@ -285,7 +318,7 @@ void DisplayApp::Refresh() { } if (nextApp != Apps::None) { - LoadApp(nextApp, nextDirection); + LoadNewScreen(nextApp, nextDirection); nextApp = Apps::None; } } @@ -295,27 +328,23 @@ void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) nextDirection = direction; } -void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) { - returnToApp = app; - returnDirection = direction; - returnTouchEvent = touchEvent; +void DisplayApp::LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction) { + returnAppStack.Push(currentApp); + appStackDirections.Push(direction); + LoadScreen(app, direction); } -void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) { +void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction) { touchHandler.CancelTap(); ApplyBrightness(); currentScreen.reset(nullptr); SetFullRefresh(direction); - // default return to launcher - ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown); - switch (app) { case Apps::Launcher: currentScreen = std::make_unique(this, settingsController, batteryController, bleController, dateTimeController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::None: case Apps::Clock: @@ -332,21 +361,17 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Error: currentScreen = std::make_unique(this, bootError); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::FirmwareValidation: currentScreen = std::make_unique(this, validator); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FirmwareUpdate: currentScreen = std::make_unique(this, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::PassKey: currentScreen = std::make_unique(this, bleController.GetPairingKey()); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::Notifications: @@ -356,7 +381,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Normal); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::NotificationsPreview: currentScreen = std::make_unique(this, @@ -365,7 +389,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Preview); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::Timer: currentScreen = std::make_unique(this, timerController); @@ -383,55 +406,42 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, settingsController, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft); break; case Apps::Settings: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWatchFace: currentScreen = std::make_unique(this, settingsController, filesystem); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingTimeFormat: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWakeUp: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingDisplay: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSteps: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSetDate: currentScreen = std::make_unique(this, dateTimeController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSetTime: currentScreen = std::make_unique(this, dateTimeController, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingChimes: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingShakeThreshold: currentScreen = std::make_unique(this, settingsController, motionController, *systemTask); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingBluetooth: currentScreen = std::make_unique(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::BatteryInfo: currentScreen = std::make_unique(this, batteryController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SysInfo: currentScreen = std::make_unique(this, @@ -442,11 +452,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) watchdog, motionController, touchPanel); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FlashLight: currentScreen = std::make_unique(this, *systemTask, brightnessController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::StopWatch: currentScreen = std::make_unique(this, *systemTask); @@ -471,7 +479,6 @@ 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/DisplayApp.h b/src/displayapp/DisplayApp.h index 4c54e227..3c1829d5 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -20,6 +20,8 @@ #include "displayapp/Messages.h" #include "BootErrors.h" +#include "StaticStack.h" + namespace Pinetime { namespace Drivers { @@ -114,14 +116,18 @@ namespace Pinetime { static void Process(void* instance); void InitHw(); void Refresh(); - void ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent); - void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction); void PushMessageToSystemTask(Pinetime::System::Messages message); Apps nextApp = Apps::None; DisplayApp::FullRefreshDirections nextDirection; System::BootErrors bootError; void ApplyBrightness(); + + static constexpr size_t returnAppStackSize = 10; + StaticStack returnAppStack; + StaticStack appStackDirections; }; } } diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index df87092b..40456ab8 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -146,7 +146,6 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) { bool Metronome::OnTouchEvent(TouchEvents event) { if (event == TouchEvents::SwipeDown && allowExit) { running = false; - return true; } - return false; + return true; }