From 35e221078bf8e7b1548f5b75c391404d098442a0 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 9 Mar 2020 21:29:12 +0100 Subject: [PATCH] Add support for gestures and integrate it with the vertical scrolling transition. --- src/DisplayApp/DisplayApp.cpp | 92 ++++++++++++----- src/DisplayApp/DisplayApp.h | 5 +- src/DisplayApp/LittleVgl.cpp | 171 ++++++++++++++++++------------- src/DisplayApp/LittleVgl.h | 13 ++- src/DisplayApp/Screens/Clock.cpp | 3 +- 5 files changed, 184 insertions(+), 100 deletions(-) diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 3c980dc9..902432ac 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -33,6 +33,7 @@ DisplayApp::DisplayApp(Pinetime::Drivers::St7789& lcd, currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) }, systemTask{systemTask} { msgQueue = xQueueCreate(queueSize, itemSize); + onClockApp = true; } void DisplayApp::Start() { @@ -112,25 +113,45 @@ void DisplayApp::Refresh() { case Messages::UpdateBatteryLevel: // clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining()); break; - case Messages::TouchEvent: - if(state != States::Running) break; - OnTouchEvent(); + case Messages::TouchEvent: { + if (state != States::Running) break; + auto gesture = OnTouchEvent(); + switch (gesture) { + case DisplayApp::TouchEvents::SwipeUp: + currentScreen->OnButtonPushed(); + lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up); + break; + case DisplayApp::TouchEvents::SwipeDown: + currentScreen->OnButtonPushed(); + lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); + break; + default: + break; + } + } break; case Messages::ButtonPushed: -// if(!currentScreen->OnButtonPushed()) { -// systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); -// } - lvgl.SetFullRefresh(); - lv_disp_set_direction(lv_disp_get_default(), 0); - currentScreen.reset(nullptr); - if(toggle) { - currentScreen.reset(new Screens::Tile(this)); - toggle = false; - } else { - currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); - toggle = true; + if(onClockApp) + systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); + else { + auto buttonUsedByApp = currentScreen->OnButtonPushed(); + if (!buttonUsedByApp) { + systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); + } else { + lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up); + } } +// lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down); +// currentScreen.reset(nullptr); +// if(toggle) { +// currentScreen.reset(new Screens::Tile(this)); +// toggle = false; +// } else { +// currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); +// toggle = true; +// } + break; } } @@ -140,12 +161,15 @@ void DisplayApp::RunningState() { // clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime()); if(!currentScreen->Refresh()) { - lvgl.SetFullRefresh(); currentScreen.reset(nullptr); + onClockApp = false; switch(nextApp) { case Apps::None: case Apps::Launcher: currentScreen.reset(new Screens::Tile(this)); break; - case Apps::Clock: currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); break; + case Apps::Clock: + currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); + onClockApp = true; + break; case Apps::Test: currentScreen.reset(new Screens::Message(this)); break; case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break; case Apps::Gauge: currentScreen.reset(new Screens::Gauge(this)); break; @@ -169,14 +193,32 @@ void DisplayApp::PushMessage(DisplayApp::Messages msg) { } } -static uint16_t pointColor = 0x07e0; -void DisplayApp::OnTouchEvent() { -// auto info = touchPanel.GetTouchInfo(); -// -// if(info.isTouch) { -// lcd.DrawPixel(info.x, info.y, pointColor); -// pointColor+=10; -// } +DisplayApp::TouchEvents DisplayApp::OnTouchEvent() { + auto info = touchPanel.GetTouchInfo(); + if(info.isTouch) { + switch(info.gesture) { + case Pinetime::Drivers::Cst816S::Gestures::SingleTap: + // TODO set x,y to LittleVgl + lvgl.SetNewTapEvent(info.x, info.y); + return DisplayApp::TouchEvents::Tap; + case Pinetime::Drivers::Cst816S::Gestures::LongPress: + return DisplayApp::TouchEvents::LongTap; + case Pinetime::Drivers::Cst816S::Gestures::DoubleTap: + return DisplayApp::TouchEvents::DoubleTap; + case Pinetime::Drivers::Cst816S::Gestures::SlideRight: + return DisplayApp::TouchEvents::SwipeRight; + case Pinetime::Drivers::Cst816S::Gestures::SlideLeft: + return DisplayApp::TouchEvents::SwipeLeft; + case Pinetime::Drivers::Cst816S::Gestures::SlideDown: + return DisplayApp::TouchEvents::SwipeDown; + case Pinetime::Drivers::Cst816S::Gestures::SlideUp: + return DisplayApp::TouchEvents::SwipeUp; + case Pinetime::Drivers::Cst816S::Gestures::None: + default: + return DisplayApp::TouchEvents::None; + } + } + return DisplayApp::TouchEvents::None; } void DisplayApp::StartApp(DisplayApp::Apps app) { diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 2505423a..eaad1baa 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -25,6 +25,8 @@ namespace Pinetime { public: enum class States {Idle, Running}; enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, SwitchScreen,ButtonPushed} ; + enum class TouchEvents { None, Tap, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, LongTap, DoubleTap + }; DisplayApp(Pinetime::Drivers::St7789& lcd, Pinetime::Components::LittleVgl& lvgl, Pinetime::Drivers::Cst816S&, @@ -59,7 +61,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Drivers::Cst816S& touchPanel; - void OnTouchEvent(); + TouchEvents OnTouchEvent(); std::unique_ptr currentScreen; static constexpr uint8_t pinLcdBacklight1 = 14; @@ -70,6 +72,7 @@ namespace Pinetime { Pinetime::System::SystemTask& systemTask; Apps nextApp = Apps::None; + bool onClockApp = false; // TODO find a better way to know that we should handle gestures and button differently for the Clock app. }; } } diff --git a/src/DisplayApp/LittleVgl.cpp b/src/DisplayApp/LittleVgl.cpp index 2796daac..1dfbc2d1 100644 --- a/src/DisplayApp/LittleVgl.cpp +++ b/src/DisplayApp/LittleVgl.cpp @@ -64,8 +64,10 @@ void LittleVgl::InitTouchpad() { lv_indev_drv_register(&indev_drv); } -void LittleVgl::SetFullRefresh() { - fullRefresh = true; +void LittleVgl::SetFullRefresh(FullRefreshDirections direction) { + scrollDirection = direction; + if(scrollDirection == FullRefreshDirections::Down) + lv_disp_set_direction(lv_disp_get_default(), 1); } void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) { @@ -74,86 +76,114 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) { // TODO refactore and remove duplicated code uint16_t x, y, y1, y2, width, height = 0; - if(fullRefresh) { - if(scrollDirection == LittleVgl::ScrollDirections::Down) { - if(area->y2 == visibleNbLines-1) { + if(scrollDirection == LittleVgl::FullRefreshDirections::Down) { + if(area->y2 == visibleNbLines-1) { writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines; - } - x = area->x1; - width = (area->x2 - area->x1) + 1; - - y1 = (area->y1 + writeOffset) % totalNbLines; - y2 = (area->y2 + writeOffset) % totalNbLines; - y = y1; - height = (y2 - y1) + 1; - - if(area->y2 < visibleNbLines - 1) { - uint16_t toScroll = 0; - if(area->y1 == 0) { - toScroll = height*2; - fullRefresh = false; - lv_disp_set_direction(lv_disp_get_default(), 0); - } else { - toScroll = height; - } - - if(scrollOffset >= toScroll) - scrollOffset -= toScroll; - else { - toScroll -= scrollOffset; - scrollOffset = (totalNbLines) - toScroll; - } - - lcd.VerticalScrollDefinition(0, 320, 0); - lcd.VerticalScrollStartAddress(scrollOffset); - } - - lcd.BeginDrawBuffer(x, y, width, height); - lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height*2) ; - - } else { - if(area->y1 == 0) { - writeOffset = (writeOffset + visibleNbLines) % totalNbLines; - } - - x = area->x1; - width = (area->x2 - area->x1) + 1; - - y1 = (area->y1 + writeOffset) % totalNbLines; - y2 = (area->y2 + writeOffset) % totalNbLines; - y = y1; - height = (y2 - y1) + 1; - - if(area->y1 > 0) { - if(area->y2 == visibleNbLines -1) { - scrollOffset += (height * 2); - fullRefresh = false; - lv_disp_set_direction(lv_disp_get_default(), 0); - } else { - scrollOffset += height; - } - scrollOffset = scrollOffset % totalNbLines; - lcd.VerticalScrollDefinition(0, 320, 0); - lcd.VerticalScrollStartAddress(scrollOffset); - } - - lcd.BeginDrawBuffer(x, y, width, height); - lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height*2); } - } else { x = area->x1; - y = area->y1; width = (area->x2 - area->x1) + 1; - height = (area->y2 - area->y1) + 1; + + y1 = (area->y1 + writeOffset) % totalNbLines; + y2 = (area->y2 + writeOffset) % totalNbLines; + y = y1; + height = (y2 - y1) + 1; + + if(area->y2 < visibleNbLines - 1) { + uint16_t toScroll = 0; + if(area->y1 == 0) { + toScroll = height*2; + scrollDirection = FullRefreshDirections::None; + lv_disp_set_direction(lv_disp_get_default(), 0); + } else { + toScroll = height; + } + + if(scrollOffset >= toScroll) + scrollOffset -= toScroll; + else { + toScroll -= scrollOffset; + scrollOffset = (totalNbLines) - toScroll; + } + + lcd.VerticalScrollDefinition(0, 320, 0); + lcd.VerticalScrollStartAddress(scrollOffset); + } + lcd.BeginDrawBuffer(x, y, width, height); lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height*2) ; + + } else if(scrollDirection == FullRefreshDirections::Up) { + if(area->y1 == 0) { + writeOffset = (writeOffset + visibleNbLines) % totalNbLines; + } + + x = area->x1; + width = (area->x2 - area->x1) + 1; + + y1 = (area->y1 + writeOffset) % totalNbLines; + y2 = (area->y2 + writeOffset) % totalNbLines; + y = y1; + height = (y2 - y1) + 1; + + if(area->y1 > 0) { + if(area->y2 == visibleNbLines -1) { + scrollOffset += (height * 2); + scrollDirection = FullRefreshDirections::None; + lv_disp_set_direction(lv_disp_get_default(), 0); + } else { + scrollOffset += height; + } + scrollOffset = scrollOffset % totalNbLines; + lcd.VerticalScrollDefinition(0, 320, 0); + lcd.VerticalScrollStartAddress(scrollOffset); + } + + lcd.BeginDrawBuffer(x, y, width, height); + lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height*2); + } else { + x = area->x1; + width = (area->x2 - area->x1) + 1; + y1 = (area->y1 + writeOffset) % totalNbLines; + y2 = (area->y2 + writeOffset) % totalNbLines; + y = y1; + height = (y2 - y1) + 1; + + if (y2 < y1) { + height = (totalNbLines - 1) - y1; + lcd.BeginDrawBuffer(x, y1, width, height); + lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height * 2); + ulTaskNotifyTake(pdTRUE, 500); + height = y2; + lcd.BeginDrawBuffer(x, 0, width, height); + lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height * 2); + } else { + lcd.BeginDrawBuffer(x, y, width, height); + lcd.NextDrawBuffer(reinterpret_cast(color_p), width * height * 2); + } } /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(&disp_drv); } + +void LittleVgl::SetNewTapEvent(uint16_t x, uint16_t y) { + tap_x = x; + tap_y = y; + tapped = true; +} + bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) { + if(tapped) { + ptr->point.x = tap_x; + ptr->point.y = tap_y; + ptr->state = LV_INDEV_STATE_PR; + tapped = false; + } else { + ptr->state = LV_INDEV_STATE_REL; + } + return false; + /* auto info = touchPanel.GetTouchInfo(); if((previousClick.x != info.x || previousClick.y != info.y) && @@ -173,6 +203,7 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) { ptr->point.x = info.x; ptr->point.y = info.y; return false; + */ } void LittleVgl::InitTheme() { @@ -790,3 +821,5 @@ void LittleVgl::InitThemeWindow() { // theme.style.win.btn.pr = &win_btn_pr; } + + diff --git a/src/DisplayApp/LittleVgl.h b/src/DisplayApp/LittleVgl.h index 555f5f0f..c6e728b2 100644 --- a/src/DisplayApp/LittleVgl.h +++ b/src/DisplayApp/LittleVgl.h @@ -14,6 +14,7 @@ namespace Pinetime { namespace Components { class LittleVgl { public: + enum class FullRefreshDirections { None, Up, Down }; LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel); LittleVgl(const LittleVgl&) = delete; @@ -23,7 +24,9 @@ namespace Pinetime { void FlushDisplay(const lv_area_t * area, lv_color_t * color_p); bool GetTouchPadInfo(lv_indev_data_t *ptr); - void SetFullRefresh(); + void SetFullRefresh(FullRefreshDirections direction); + void SetNewTapEvent(uint16_t x, uint16_t y); + private: void InitDisplay(); void InitTouchpad(); @@ -99,15 +102,17 @@ namespace Pinetime { lv_style_t win_btn_pr; bool firstTouch = true; - bool fullRefresh = false; static constexpr uint8_t nbWriteLines = 4; static constexpr uint16_t totalNbLines = 320; static constexpr uint16_t visibleNbLines = 240; static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; } - enum class ScrollDirections {Unknown, Up, Down}; - ScrollDirections scrollDirection = ScrollDirections::Up; + FullRefreshDirections scrollDirection = FullRefreshDirections::None; uint16_t writeOffset = 0; uint16_t scrollOffset = 0; + + uint16_t tap_x = 0; + uint16_t tap_y = 0; + bool tapped = false; }; } } diff --git a/src/DisplayApp/Screens/Clock.cpp b/src/DisplayApp/Screens/Clock.cpp index 7051c433..abc4d627 100644 --- a/src/DisplayApp/Screens/Clock.cpp +++ b/src/DisplayApp/Screens/Clock.cpp @@ -184,7 +184,8 @@ void Clock::OnObjectEvent(lv_obj_t *obj, lv_event_t event) { } bool Clock::OnButtonPushed() { - return Screen::OnButtonPushed(); + running = false; + return false; }