Add support for gestures and integrate it with the vertical scrolling transition.

This commit is contained in:
JF 2020-03-09 21:29:12 +01:00
parent 968f18f472
commit 35e221078b
5 changed files with 184 additions and 100 deletions

View file

@ -33,6 +33,7 @@ DisplayApp::DisplayApp(Pinetime::Drivers::St7789& lcd,
currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) }, currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) },
systemTask{systemTask} { systemTask{systemTask} {
msgQueue = xQueueCreate(queueSize, itemSize); msgQueue = xQueueCreate(queueSize, itemSize);
onClockApp = true;
} }
void DisplayApp::Start() { void DisplayApp::Start() {
@ -112,24 +113,44 @@ void DisplayApp::Refresh() {
case Messages::UpdateBatteryLevel: case Messages::UpdateBatteryLevel:
// clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining()); // clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining());
break; break;
case Messages::TouchEvent: case Messages::TouchEvent: {
if(state != States::Running) break; if (state != States::Running) break;
OnTouchEvent(); 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; break;
case Messages::ButtonPushed: case Messages::ButtonPushed:
// if(!currentScreen->OnButtonPushed()) { if(onClockApp)
// systemTask.PushMessage(System::SystemTask::Messages::GoToSleep); systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
// } else {
lvgl.SetFullRefresh(); auto buttonUsedByApp = currentScreen->OnButtonPushed();
lv_disp_set_direction(lv_disp_get_default(), 0); if (!buttonUsedByApp) {
currentScreen.reset(nullptr); systemTask.PushMessage(System::SystemTask::Messages::GoToSleep);
if(toggle) {
currentScreen.reset(new Screens::Tile(this));
toggle = false;
} else { } else {
currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController)); lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up);
toggle = true;
} }
}
// 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; break;
} }
@ -140,12 +161,15 @@ void DisplayApp::RunningState() {
// clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime()); // clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime());
if(!currentScreen->Refresh()) { if(!currentScreen->Refresh()) {
lvgl.SetFullRefresh();
currentScreen.reset(nullptr); currentScreen.reset(nullptr);
onClockApp = false;
switch(nextApp) { switch(nextApp) {
case Apps::None: case Apps::None:
case Apps::Launcher: currentScreen.reset(new Screens::Tile(this)); break; 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::Test: currentScreen.reset(new Screens::Message(this)); break;
case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break; case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break;
case Apps::Gauge: currentScreen.reset(new Screens::Gauge(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; DisplayApp::TouchEvents DisplayApp::OnTouchEvent() {
void DisplayApp::OnTouchEvent() { auto info = touchPanel.GetTouchInfo();
// auto info = touchPanel.GetTouchInfo(); if(info.isTouch) {
// switch(info.gesture) {
// if(info.isTouch) { case Pinetime::Drivers::Cst816S::Gestures::SingleTap:
// lcd.DrawPixel(info.x, info.y, pointColor); // TODO set x,y to LittleVgl
// pointColor+=10; 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) { void DisplayApp::StartApp(DisplayApp::Apps app) {

View file

@ -25,6 +25,8 @@ namespace Pinetime {
public: public:
enum class States {Idle, Running}; enum class States {Idle, Running};
enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, SwitchScreen,ButtonPushed} ; 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, DisplayApp(Pinetime::Drivers::St7789& lcd,
Pinetime::Components::LittleVgl& lvgl, Pinetime::Components::LittleVgl& lvgl,
Pinetime::Drivers::Cst816S&, Pinetime::Drivers::Cst816S&,
@ -59,7 +61,7 @@ namespace Pinetime {
Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Drivers::Cst816S& touchPanel; Pinetime::Drivers::Cst816S& touchPanel;
void OnTouchEvent(); TouchEvents OnTouchEvent();
std::unique_ptr<Screens::Screen> currentScreen; std::unique_ptr<Screens::Screen> currentScreen;
static constexpr uint8_t pinLcdBacklight1 = 14; static constexpr uint8_t pinLcdBacklight1 = 14;
@ -70,6 +72,7 @@ namespace Pinetime {
Pinetime::System::SystemTask& systemTask; Pinetime::System::SystemTask& systemTask;
Apps nextApp = Apps::None; 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.
}; };
} }
} }

View file

@ -64,8 +64,10 @@ void LittleVgl::InitTouchpad() {
lv_indev_drv_register(&indev_drv); lv_indev_drv_register(&indev_drv);
} }
void LittleVgl::SetFullRefresh() { void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
fullRefresh = true; 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) { void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
@ -74,8 +76,7 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
// TODO refactore and remove duplicated code // TODO refactore and remove duplicated code
uint16_t x, y, y1, y2, width, height = 0; uint16_t x, y, y1, y2, width, height = 0;
if(fullRefresh) { if(scrollDirection == LittleVgl::FullRefreshDirections::Down) {
if(scrollDirection == LittleVgl::ScrollDirections::Down) {
if(area->y2 == visibleNbLines-1) { if(area->y2 == visibleNbLines-1) {
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines; writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
} }
@ -91,7 +92,7 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
uint16_t toScroll = 0; uint16_t toScroll = 0;
if(area->y1 == 0) { if(area->y1 == 0) {
toScroll = height*2; toScroll = height*2;
fullRefresh = false; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
} else { } else {
toScroll = height; toScroll = height;
@ -111,7 +112,7 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
lcd.BeginDrawBuffer(x, y, width, height); lcd.BeginDrawBuffer(x, y, width, height);
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height*2) ; lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height*2) ;
} else { } else if(scrollDirection == FullRefreshDirections::Up) {
if(area->y1 == 0) { if(area->y1 == 0) {
writeOffset = (writeOffset + visibleNbLines) % totalNbLines; writeOffset = (writeOffset + visibleNbLines) % totalNbLines;
} }
@ -127,7 +128,7 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
if(area->y1 > 0) { if(area->y1 > 0) {
if(area->y2 == visibleNbLines -1) { if(area->y2 == visibleNbLines -1) {
scrollOffset += (height * 2); scrollOffset += (height * 2);
fullRefresh = false; scrollDirection = FullRefreshDirections::None;
lv_disp_set_direction(lv_disp_get_default(), 0); lv_disp_set_direction(lv_disp_get_default(), 0);
} else { } else {
scrollOffset += height; scrollOffset += height;
@ -139,21 +140,50 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
lcd.BeginDrawBuffer(x, y, width, height); lcd.BeginDrawBuffer(x, y, width, height);
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height*2); lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height*2);
}
} else { } else {
x = area->x1; x = area->x1;
y = area->y1;
width = (area->x2 - area->x1) + 1; 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 (y2 < y1) {
height = (totalNbLines - 1) - y1;
lcd.BeginDrawBuffer(x, y1, width, height);
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
ulTaskNotifyTake(pdTRUE, 500);
height = y2;
lcd.BeginDrawBuffer(x, 0, width, height);
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
} else {
lcd.BeginDrawBuffer(x, y, width, height); lcd.BeginDrawBuffer(x, y, width, height);
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height*2) ; lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(color_p), width * height * 2);
}
} }
/* IMPORTANT!!! /* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/ * Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(&disp_drv); 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) { 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(); auto info = touchPanel.GetTouchInfo();
if((previousClick.x != info.x || previousClick.y != info.y) && 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.x = info.x;
ptr->point.y = info.y; ptr->point.y = info.y;
return false; return false;
*/
} }
void LittleVgl::InitTheme() { void LittleVgl::InitTheme() {
@ -790,3 +821,5 @@ void LittleVgl::InitThemeWindow() {
// theme.style.win.btn.pr = &win_btn_pr; // theme.style.win.btn.pr = &win_btn_pr;
} }

View file

@ -14,6 +14,7 @@ namespace Pinetime {
namespace Components { namespace Components {
class LittleVgl { class LittleVgl {
public: public:
enum class FullRefreshDirections { None, Up, Down };
LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel); LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
LittleVgl(const LittleVgl&) = delete; LittleVgl(const LittleVgl&) = delete;
@ -23,7 +24,9 @@ namespace Pinetime {
void FlushDisplay(const lv_area_t * area, lv_color_t * color_p); void FlushDisplay(const lv_area_t * area, lv_color_t * color_p);
bool GetTouchPadInfo(lv_indev_data_t *ptr); bool GetTouchPadInfo(lv_indev_data_t *ptr);
void SetFullRefresh(); void SetFullRefresh(FullRefreshDirections direction);
void SetNewTapEvent(uint16_t x, uint16_t y);
private: private:
void InitDisplay(); void InitDisplay();
void InitTouchpad(); void InitTouchpad();
@ -99,15 +102,17 @@ namespace Pinetime {
lv_style_t win_btn_pr; lv_style_t win_btn_pr;
bool firstTouch = true; bool firstTouch = true;
bool fullRefresh = false;
static constexpr uint8_t nbWriteLines = 4; static constexpr uint8_t nbWriteLines = 4;
static constexpr uint16_t totalNbLines = 320; static constexpr uint16_t totalNbLines = 320;
static constexpr uint16_t visibleNbLines = 240; static constexpr uint16_t visibleNbLines = 240;
static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; } static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; }
enum class ScrollDirections {Unknown, Up, Down}; FullRefreshDirections scrollDirection = FullRefreshDirections::None;
ScrollDirections scrollDirection = ScrollDirections::Up;
uint16_t writeOffset = 0; uint16_t writeOffset = 0;
uint16_t scrollOffset = 0; uint16_t scrollOffset = 0;
uint16_t tap_x = 0;
uint16_t tap_y = 0;
bool tapped = false;
}; };
} }
} }

View file

@ -184,7 +184,8 @@ void Clock::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
} }
bool Clock::OnButtonPushed() { bool Clock::OnButtonPushed() {
return Screen::OnButtonPushed(); running = false;
return false;
} }