Add support for gestures and integrate it with the vertical scrolling transition.
This commit is contained in:
parent
968f18f472
commit
35e221078b
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue