Add touch panel port to lvgl.

PoC of user interaction with 3 screen (clock, menu and app).
main
JF 2020-02-16 18:32:36 +07:00
parent 52539a5ff1
commit 167a0ffc87
18 changed files with 540 additions and 68 deletions

@ -137,6 +137,19 @@ set(LVGL_SRC
libs/lvgl/src/lv_themes/lv_theme_night.h libs/lvgl/src/lv_themes/lv_theme_night.h
libs/lvgl/src/lv_themes/lv_theme_night.c libs/lvgl/src/lv_themes/lv_theme_night.c
libs/lvgl/src/lv_objx/lv_list.c
libs/lvgl/src/lv_objx/lv_list.h
libs/lvgl/src/lv_objx/lv_tileview.c
libs/lvgl/src/lv_objx/lv_tileview.h
libs/lvgl/src/lv_objx/lv_tabview.c
libs/lvgl/src/lv_objx/lv_tabview.h
libs/lvgl/src/lv_objx/lv_btnm.c
libs/lvgl/src/lv_objx/lv_btnm.h
libs/lvgl/src/lv_objx/lv_page.c
libs/lvgl/src/lv_objx/lv_page.h
libs/lvgl/src/lv_objx/lv_img.c
libs/lvgl/src/lv_objx/lv_img.h
) )
list(APPEND SOURCE_FILES list(APPEND SOURCE_FILES
@ -148,6 +161,8 @@ list(APPEND SOURCE_FILES
DisplayApp/Screens/Screen.cpp DisplayApp/Screens/Screen.cpp
DisplayApp/Screens/Clock.cpp DisplayApp/Screens/Clock.cpp
DisplayApp/Screens/Message.cpp DisplayApp/Screens/Message.cpp
DisplayApp/Screens/Tile.cpp
DisplayApp/Screens/Tab.cpp
main.cpp main.cpp
drivers/St7789.cpp drivers/St7789.cpp
drivers/SpiMaster.cpp drivers/SpiMaster.cpp
@ -177,6 +192,8 @@ set(INCLUDE_FILES
DisplayApp/Screens/Screen.h DisplayApp/Screens/Screen.h
DisplayApp/Screens/Clock.h DisplayApp/Screens/Clock.h
DisplayApp/Screens/Message.h DisplayApp/Screens/Message.h
DisplayApp/Screens/Tile.h
DisplayApp/Screens/Tab.h
drivers/St7789.h drivers/St7789.h
drivers/SpiMaster.h drivers/SpiMaster.h
Components/Gfx/Gfx.h Components/Gfx/Gfx.h

@ -49,7 +49,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
previousSystickCounter = 0xffffff - (rest - systickCounter); previousSystickCounter = 0xffffff - (rest - systickCounter);
} }
currentDateTime += std::chrono::milliseconds (systickDelta*10); currentDateTime += std::chrono::seconds (correctedDelta);
auto dp = date::floor<date::days>(currentDateTime); auto dp = date::floor<date::days>(currentDateTime);
auto time = date::make_time(currentDateTime-dp); auto time = date::make_time(currentDateTime-dp);

@ -12,6 +12,8 @@
#include <chrono> #include <chrono>
#include <string> #include <string>
#include <lvgl/lvgl.h> #include <lvgl/lvgl.h>
#include <DisplayApp/Screens/Tile.h>
#include <DisplayApp/Screens/Tab.h>
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
@ -29,14 +31,12 @@ DisplayApp::DisplayApp(Pinetime::Drivers::St7789& lcd,
batteryController{batteryController}, batteryController{batteryController},
bleController{bleController}, bleController{bleController},
dateTimeController{dateTimeController}, dateTimeController{dateTimeController},
clockScreen{gfx}, currentScreen{new Screens::Tile(this, gfx) } {
messageScreen{gfx}{
msgQueue = xQueueCreate(queueSize, itemSize); msgQueue = xQueueCreate(queueSize, itemSize);
currentScreen = &clockScreen;
} }
void DisplayApp::Start() { void DisplayApp::Start() {
if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 1024, this, 0, &taskHandle)) if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 512, this, 0, &taskHandle))
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
} }
@ -73,7 +73,7 @@ void DisplayApp::Refresh() {
break; break;
case States::Running: case States::Running:
RunningState(); RunningState();
queueTimeout = 1000; queueTimeout = 20;
break; break;
} }
@ -104,15 +104,17 @@ void DisplayApp::Refresh() {
case Messages::UpdateDateTime: case Messages::UpdateDateTime:
break; break;
case Messages::UpdateBleConnection: case Messages::UpdateBleConnection:
clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected); // clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected);
break; break;
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(); OnTouchEvent();
break; break;
case Messages::ButtonPushed:
currentScreen->OnButtonPushed();
} }
} }
} }
@ -120,10 +122,26 @@ void DisplayApp::Refresh() {
bool first = true; bool first = true;
void DisplayApp::RunningState() { void DisplayApp::RunningState() {
clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime()); // clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime());
if(currentScreen != nullptr) { if(currentScreen != nullptr) {
currentScreen->Refresh(first); currentScreen->Refresh(first);
if(currentScreen->GetNextScreen() != Screens::Screen::NextScreen::None) {
switch(currentScreen->GetNextScreen()) {
case Screens::Screen::NextScreen::Clock:
currentScreen.reset(nullptr);
currentScreen.reset(new Screens::Clock(this, gfx, dateTimeController));
break;
case Screens::Screen::NextScreen::Menu:
currentScreen.reset(nullptr);
currentScreen.reset(new Screens::Tile(this, gfx));
break;
case Screens::Screen::NextScreen::App:
currentScreen.reset(nullptr);
currentScreen.reset(new Screens::Message(this, gfx));
break;
}
}
first = false; first = false;
} }
} }
@ -144,10 +162,10 @@ void DisplayApp::PushMessage(DisplayApp::Messages msg) {
static uint16_t pointColor = 0x07e0; static uint16_t pointColor = 0x07e0;
void DisplayApp::OnTouchEvent() { void DisplayApp::OnTouchEvent() {
auto info = touchPanel.GetTouchInfo(); // auto info = touchPanel.GetTouchInfo();
//
if(info.isTouch) { // if(info.isTouch) {
gfx.FillRectangle(info.x-10, info.y-10, 20,20, pointColor); // gfx.FillRectangle(info.x-10, info.y-10, 20,20, pointColor);
pointColor+=10; // pointColor+=10;
} // }
} }

@ -23,7 +23,7 @@ namespace Pinetime {
class DisplayApp { class DisplayApp {
public: public:
enum class States {Idle, Running}; enum class States {Idle, Running};
enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent} ; enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, SwitchScreen,ButtonPushed} ;
DisplayApp(Pinetime::Drivers::St7789& lcd, DisplayApp(Pinetime::Drivers::St7789& lcd,
Pinetime::Components::Gfx& gfx, Pinetime::Components::Gfx& gfx,
Pinetime::Components::LittleVgl& lvgl, Pinetime::Components::LittleVgl& lvgl,
@ -60,12 +60,12 @@ namespace Pinetime {
Pinetime::Drivers::Cst816S& touchPanel; Pinetime::Drivers::Cst816S& touchPanel;
void OnTouchEvent(); void OnTouchEvent();
Screens::Clock clockScreen; std::unique_ptr<Screens::Screen> currentScreen;
Screens::Message messageScreen;
Screens::Screen* currentScreen = nullptr;
static constexpr uint8_t pinLcdBacklight1 = 14; static constexpr uint8_t pinLcdBacklight1 = 14;
static constexpr uint8_t pinLcdBacklight2 = 22; static constexpr uint8_t pinLcdBacklight2 = 22;
static constexpr uint8_t pinLcdBacklight3 = 23; static constexpr uint8_t pinLcdBacklight3 = 23;
bool isClock = true;
}; };
} }
} }

@ -17,8 +17,18 @@ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_colo
lvgl->FlushDisplay(area, color_p); lvgl->FlushDisplay(area, color_p);
} }
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd) : lcd{lcd} { bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
auto* lvgl = static_cast<LittleVgl*>(indev_drv->user_data);
return lvgl->GetTouchPadInfo(data);
}
LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) : lcd{lcd}, touchPanel{touchPanel} {
lv_init(); lv_init();
InitDisplay();
InitTouchpad();
}
void LittleVgl::InitDisplay() {
lv_theme_t* theme = lv_theme_night_init(10, NULL); lv_theme_t* theme = lv_theme_night_init(10, NULL);
lv_theme_set_current(theme); lv_theme_set_current(theme);
@ -39,8 +49,16 @@ LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd) : lcd{lcd} {
/*Finally register the driver*/ /*Finally register the driver*/
lv_disp_drv_register(&disp_drv); lv_disp_drv_register(&disp_drv);
}
void LittleVgl::InitTouchpad() {
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
indev_drv.user_data = this;
lv_indev_drv_register(&indev_drv);
} }
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) {
@ -57,3 +75,21 @@ void LittleVgl::FlushDisplay(const lv_area_t *area, lv_color_t *color_p) {
* 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);
} }
bool LittleVgl::GetTouchPadInfo(lv_indev_data_t *ptr) {
auto info = touchPanel.GetTouchInfo();
if((previousClick.x != info.x || previousClick.y != info.y) &&
(info.gesture == Drivers::Cst816S::Gestures::SingleTap)) {
ptr->state = LV_INDEV_STATE_PR;
previousClick.x = ptr->point.x;
previousClick.y = ptr->point.y;
}
else {
ptr->state = LV_INDEV_STATE_REL;
}
ptr->point.x = info.x;
ptr->point.y = info.y;
return false;
}

@ -2,26 +2,36 @@
#include <libs/lvgl/src/lv_hal/lv_hal.h> #include <libs/lvgl/src/lv_hal/lv_hal.h>
#include <drivers/St7789.h> #include <drivers/St7789.h>
#include <drivers/Cst816s.h>
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
namespace Pinetime { namespace Pinetime {
namespace Components { namespace Components {
class LittleVgl { class LittleVgl {
public: public:
LittleVgl(Pinetime::Drivers::St7789& lcd); LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel);
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);
private: private:
void InitDisplay();
void InitTouchpad();
Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::St7789& lcd;
Pinetime::Drivers::Cst816S& touchPanel;
lv_disp_buf_t disp_buf_2; lv_disp_buf_t disp_buf_2;
lv_color_t buf2_1[LV_HOR_RES_MAX * 2]; lv_color_t buf2_1[LV_HOR_RES_MAX * 2];
lv_color_t buf2_2[LV_HOR_RES_MAX * 2]; lv_color_t buf2_2[LV_HOR_RES_MAX * 2];
lv_disp_drv_t disp_drv; lv_disp_drv_t disp_drv;
lv_point_t previousClick;
}; };
} }

@ -4,12 +4,24 @@
#include <Version.h> #include <Version.h>
#include <libs/lvgl/lvgl.h> #include <libs/lvgl/lvgl.h>
#include "Clock.h" #include "Clock.h"
#include "../DisplayApp.h"
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_extrabold_compressedextrabold_compressed; extern lv_font_t jetbrains_mono_extrabold_compressedextrabold_compressed;
extern lv_font_t jetbrains_mono_bold_20; extern lv_font_t jetbrains_mono_bold_20;
Clock::Clock(Pinetime::Components::Gfx &gfx) : Screen(gfx), currentDateTime{{}}, version {{}} { static void event_handler(lv_obj_t * obj, lv_event_t event) {
Clock* screen = static_cast<Clock *>(obj->user_data);
screen->OnObjectEvent(obj, event);
}
Clock::Clock(DisplayApp* app, Pinetime::Components::Gfx &gfx, Controllers::DateTime& dateTimeController) : Screen(app, gfx), currentDateTime{{}}, version {{}}, dateTimeController{dateTimeController} {
displayedChar[0] = 0;
displayedChar[1] = 0;
displayedChar[2] = 0;
displayedChar[3] = 0;
displayedChar[4] = 0;
label_battery = lv_label_create(lv_scr_act(), NULL); label_battery = lv_label_create(lv_scr_act(), NULL);
lv_obj_align(label_battery, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -80, 0); lv_obj_align(label_battery, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -80, 0);
@ -38,11 +50,24 @@ Clock::Clock(Pinetime::Components::Gfx &gfx) : Screen(gfx), currentDateTime{{}},
lv_label_set_style(label_version, LV_LABEL_STYLE_MAIN, labelStyle); lv_label_set_style(label_version, LV_LABEL_STYLE_MAIN, labelStyle);
lv_obj_align(label_version, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 100); lv_obj_align(label_version, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 100);
backgroundLabel = lv_label_create(lv_scr_act(), NULL);
backgroundLabel->user_data = this;
lv_label_set_style(backgroundLabel, LV_LABEL_STYLE_MAIN, labelStyle);
lv_obj_set_click(backgroundLabel, true);
lv_obj_set_event_cb(backgroundLabel, event_handler);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text(backgroundLabel, "");
}
Clock::~Clock() {
lv_obj_clean(lv_scr_act());
} }
void Clock::Refresh(bool fullRefresh) { void Clock::Refresh(bool fullRefresh) {
if(fullRefresh) { if(fullRefresh) {
auto dummy = currentDateTime.Get(); auto currentDateTime = dateTimeController.CurrentDateTime();
} }
if (fullRefresh || batteryPercentRemaining.IsUpdated()) { if (fullRefresh || batteryPercentRemaining.IsUpdated()) {
@ -62,6 +87,8 @@ void Clock::Refresh(bool fullRefresh) {
// TODO color // TODO color
} }
currentDateTime = dateTimeController.CurrentDateTime();
if(fullRefresh || currentDateTime.IsUpdated()) { if(fullRefresh || currentDateTime.IsUpdated()) {
auto newDateTime = currentDateTime.Get(); auto newDateTime = currentDateTime.Get();
@ -86,10 +113,17 @@ void Clock::Refresh(bool fullRefresh) {
char timeStr[6]; char timeStr[6];
sprintf(timeStr, "%c%c:%c%c", hoursChar[0],hoursChar[1],minutesChar[0], minutesChar[1]); sprintf(timeStr, "%c%c:%c%c", hoursChar[0],hoursChar[1],minutesChar[0], minutesChar[1]);
if(hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || minutesChar[1] != displayedChar[3]) {
displayedChar[0] = hoursChar[0];
displayedChar[1] = hoursChar[1];
displayedChar[2] = minutesChar[0];
displayedChar[3] = minutesChar[1];
lv_label_set_text(label_time, timeStr); lv_label_set_text(label_time, timeStr);
}
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
gfx.FillRectangle(0,180, 240, 15, 0x0000);
char dateStr[22]; char dateStr[22];
sprintf(dateStr, "%s %d %s %d", DayOfWeekToString(dayOfWeek), day, MonthToString(month), year); sprintf(dateStr, "%s %d %s %d", DayOfWeekToString(dayOfWeek), day, MonthToString(month), year);
lv_label_set_text(label_date, dateStr); lv_label_set_text(label_date, dateStr);
@ -103,9 +137,10 @@ void Clock::Refresh(bool fullRefresh) {
} }
if(fullRefresh || version.IsUpdated()) { if(fullRefresh || version.IsUpdated()) {
char version[20]; auto dummy = version.Get();
sprintf(version, "VERSION: %d.%d.%d", Version::Major(), Version::Minor(), Version::Patch()); char versionStr[20];
lv_label_set_text(label_version, version); sprintf(versionStr, "VERSION: %d.%d.%d", Version::Major(), Version::Minor(), Version::Patch());
lv_label_set_text(label_version, versionStr);
} }
} }
@ -145,4 +180,12 @@ char const *Clock::MonthsString[] = {
"DEC" "DEC"
}; };
void Clock::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
if(obj == backgroundLabel) {
if (event == LV_EVENT_CLICKED) {
nextScreen = NextScreen::Menu;
}
}
}

@ -21,7 +21,7 @@ namespace Pinetime {
explicit DirtyValue(T v) { value = v; } explicit DirtyValue(T v) { value = v; }
explicit DirtyValue(T& v) { value = v; } explicit DirtyValue(T& v) { value = v; }
bool IsUpdated() const { return isUpdated; } bool IsUpdated() const { return isUpdated; }
T& Get() { return value; this->isUpdated = false;} T& Get() { this->isUpdated = false; return value; }
DirtyValue& operator=(const T& other) { DirtyValue& operator=(const T& other) {
this->value = other; this->value = other;
@ -35,19 +35,23 @@ namespace Pinetime {
class Clock : public Screen{ class Clock : public Screen{
public: public:
enum class BleConnectionStates{ NotConnected, Connected}; enum class BleConnectionStates{ NotConnected, Connected};
Clock(Components::Gfx& gfx); Clock(DisplayApp* app, Components::Gfx& gfx, Controllers::DateTime& dateTimeController);
~Clock() override;
void Refresh(bool fullRefresh) override; void Refresh(bool fullRefresh) override;
void SetBatteryPercentRemaining(uint8_t percent) { batteryPercentRemaining = percent; } void SetBatteryPercentRemaining(uint8_t percent) { batteryPercentRemaining = percent; }
void SetBleConnectionState(BleConnectionStates state) { bleState = state; } void SetBleConnectionState(BleConnectionStates state) { bleState = state; }
void SetCurrentDateTime(const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>& tp) { currentDateTime = tp;} void SetCurrentDateTime(const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>& tp) { currentDateTime = tp;}
void OnObjectEvent(lv_obj_t *pObj, lv_event_t i);
private: private:
static const char* MonthToString(Pinetime::Controllers::DateTime::Months month); static const char* MonthToString(Pinetime::Controllers::DateTime::Months month);
static const char* DayOfWeekToString(Pinetime::Controllers::DateTime::Days dayOfWeek); static const char* DayOfWeekToString(Pinetime::Controllers::DateTime::Days dayOfWeek);
static char const *DaysString[]; static char const *DaysString[];
static char const *MonthsString[]; static char const *MonthsString[];
char displayedChar[5];
const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data}; const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data};
const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data}; const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data};
@ -69,6 +73,9 @@ namespace Pinetime {
lv_obj_t* label_time; lv_obj_t* label_time;
lv_obj_t* label_date; lv_obj_t* label_date;
lv_obj_t* label_version; lv_obj_t* label_version;
lv_obj_t* backgroundLabel;
Controllers::DateTime& dateTimeController;
}; };
} }

@ -5,24 +5,77 @@
#include <libs/lvgl/src/lv_core/lv_obj.h> #include <libs/lvgl/src/lv_core/lv_obj.h>
#include <libs/lvgl/src/lv_font/lv_font.h> #include <libs/lvgl/src/lv_font/lv_font.h>
#include <libs/lvgl/lvgl.h> #include <libs/lvgl/lvgl.h>
#include <libraries/log/nrf_log.h>
#include "Message.h" #include "Message.h"
#include <DisplayApp/DisplayApp.h>
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_extrabold_compressedextrabold_compressed; extern lv_font_t jetbrains_mono_bold_20;
lv_obj_t * label; static void event_handler(lv_obj_t * obj, lv_event_t event) {
int x = 0; Message* screen = static_cast<Message *>(obj->user_data);
void Message::Refresh(bool fullRefresh) { screen->OnObjectEvent(obj, event);
if(fullRefresh) { }
label = lv_label_create(lv_scr_act(), NULL); /*Add a label to the button*/
labelStyle = const_cast<lv_style_t *>(lv_label_get_style(label, LV_LABEL_STYLE_MAIN)); Message::Message(DisplayApp* app, Pinetime::Components::Gfx &gfx) : Screen(app, gfx) {
labelStyle->text.font = &jetbrains_mono_extrabold_compressedextrabold_compressed;
backgroundLabel = lv_label_create(lv_scr_act(), NULL);
backgroundLabel->user_data = this;
labelStyle = const_cast<lv_style_t *>(lv_label_get_style(backgroundLabel, LV_LABEL_STYLE_MAIN));
labelStyle->text.font = &jetbrains_mono_bold_20;
lv_label_set_style(backgroundLabel, LV_LABEL_STYLE_MAIN, labelStyle);
lv_obj_set_click(backgroundLabel, true);
lv_obj_set_event_cb(backgroundLabel, event_handler);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text(backgroundLabel, "");
// lv_obj_align(backgroundLabel, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
button = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(button, event_handler);
lv_obj_align(button, NULL, LV_ALIGN_CENTER, 0, -40);
button->user_data = this;
label = lv_label_create(button, NULL);
lv_label_set_style(label, LV_LABEL_STYLE_MAIN, labelStyle); lv_label_set_style(label, LV_LABEL_STYLE_MAIN, labelStyle);
lv_label_set_text(label, "01:23"); /*Set the labels text*/ lv_label_set_text(label, "Hello!");
} else {
lv_obj_set_pos(label, 0, x++); labelClick = lv_label_create(lv_scr_act(), NULL);
if(x > 200) x = 0; lv_label_set_style(labelClick, LV_LABEL_STYLE_MAIN, labelStyle);
lv_obj_align(labelClick, button, LV_ALIGN_OUT_BOTTOM_MID, 0, 30);
lv_label_set_text(labelClick, "0");
} }
Message::~Message() {
lv_obj_clean(lv_scr_act());
}
void Message::Refresh(bool fullRefresh) {
if(previousClickCount != clickCount) {
lv_label_set_text_fmt(labelClick, "%d", clickCount);
previousClickCount = clickCount;
}
}
void Message::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
if(obj == backgroundLabel) {
if(event == LV_EVENT_CLICKED) {
app->PushMessage(DisplayApp::Messages::SwitchScreen);
NRF_LOG_INFO("SCREEN");
}
return ;
}
if(event == LV_EVENT_CLICKED) {
NRF_LOG_INFO("Clicked");
clickCount++;
}
else if(event == LV_EVENT_VALUE_CHANGED) {
NRF_LOG_INFO("Toggled");
}
} }

@ -15,14 +15,24 @@ namespace Pinetime {
namespace Screens { namespace Screens {
class Message : public Screen{ class Message : public Screen{
public: public:
Message(Components::Gfx& gfx) : Screen(gfx) {} explicit Message(DisplayApp* app, Components::Gfx& gfx);
~Message() override;
void Refresh(bool fullRefresh) override; void Refresh(bool fullRefresh) override;
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
void OnButtonPushed() override { nextScreen = Screen::NextScreen::Menu; }
private: private:
const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data}; const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data};
const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data}; const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data};
lv_style_t* labelStyle; lv_style_t* labelStyle;
lv_obj_t * label;
lv_obj_t* backgroundLabel;
lv_obj_t * button;
lv_obj_t * labelClick;
uint32_t clickCount = 0 ;
uint32_t previousClickCount = 0;
}; };
} }
} }

@ -4,14 +4,21 @@
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {
class DisplayApp;
namespace Screens { namespace Screens {
class Screen { class Screen {
public: public:
Screen(Components::Gfx& gfx) : gfx{gfx} {} enum class NextScreen {None, Clock, Menu, App};
Screen(DisplayApp* app, Components::Gfx& gfx) : app{app}, gfx{gfx} {}
virtual ~Screen() = default;
virtual void Refresh(bool fullRefresh) = 0; virtual void Refresh(bool fullRefresh) = 0;
NextScreen GetNextScreen() {return nextScreen;}
virtual void OnButtonPushed() {};
protected: protected:
DisplayApp* app;
Components::Gfx& gfx; Components::Gfx& gfx;
NextScreen nextScreen = NextScreen::None;
}; };
} }
} }

@ -0,0 +1,67 @@
#include <cstdio>
#include <libs/date/includes/date/date.h>
#include <Components/DateTime/DateTimeController.h>
#include <Version.h>
#include <libs/lvgl/src/lv_core/lv_obj.h>
#include <libs/lvgl/src/lv_font/lv_font.h>
#include <libs/lvgl/lvgl.h>
#include <libraries/log/nrf_log.h>
#include "Tab.h"
#include <DisplayApp/DisplayApp.h>
using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_bold_20;
//static void event_handler(lv_obj_t * obj, lv_event_t event) {
// Tile* screen = static_cast<Tile *>(obj->user_data);
// screen->OnObjectEvent(obj, event);
//}
Tab::Tab(DisplayApp* app, Pinetime::Components::Gfx &gfx) : Screen(app, gfx) {
/*Create a Tab view object*/
lv_obj_t *tabview;
tabview = lv_tabview_create(lv_scr_act(), NULL);
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Tab 1");
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Tab 2");
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Tab 3");
/*Add content to the tabs*/
lv_obj_t * label = lv_label_create(tab1, NULL);
lv_label_set_text(label, "This the first tab\n\n"
"If the content\n"
"of a tab\n"
"become too long\n"
"the it \n"
"automatically\n"
"become\n"
"scrollable.");
label = lv_label_create(tab2, NULL);
lv_label_set_text(label, "Second tab");
label = lv_label_create(tab3, NULL);
lv_label_set_text(label, "Third tab");
}
Tab::~Tab() {
lv_obj_clean(lv_scr_act());
}
void Tab::Refresh(bool fullRefresh) {
}
void Tab::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_CLICKED) {
NRF_LOG_INFO("Clicked");
}
else if(event == LV_EVENT_VALUE_CHANGED) {
NRF_LOG_INFO("Toggled");
}
}

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <chrono>
#include <Components/Gfx/Gfx.h>
#include "Screen.h"
#include <bits/unique_ptr.h>
#include "../Fonts/lcdfont14.h"
#include "../Fonts/lcdfont70.h"
#include "../../Version.h"
#include <lvgl/src/lv_core/lv_style.h>
namespace Pinetime {
namespace Applications {
namespace Screens {
class Tab : public Screen {
public:
explicit Tab(DisplayApp* app, Components::Gfx& gfx);
~Tab() override;
void Refresh(bool fullRefresh) override;
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
private:
};
}
}
}

@ -0,0 +1,118 @@
#include <cstdio>
#include <libs/date/includes/date/date.h>
#include <Components/DateTime/DateTimeController.h>
#include <Version.h>
#include <libs/lvgl/src/lv_core/lv_obj.h>
#include <libs/lvgl/src/lv_font/lv_font.h>
#include <libs/lvgl/lvgl.h>
#include <libraries/log/nrf_log.h>
#include "Tile.h"
#include <DisplayApp/DisplayApp.h>
#include <libs/lvgl/src/lv_core/lv_style.h>
using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_bold_20;
static void event_handler(lv_obj_t * obj, lv_event_t event) {
Tile* screen = static_cast<Tile *>(obj->user_data);
screen->OnObjectEvent(obj, event);
}
//static const char * btnm_map1[] = {"App1", "App2", "App3", "\n", "App4", "App5", "App11", ""};
//static const char * btnm_map2[] = {"App6", "App7", "App8", "\n", "App9", "App10", "App22",""};
static const char * btnm_map1[] = {"App1", ""};
Tile::Tile(DisplayApp* app, Pinetime::Components::Gfx &gfx) : Screen(app, gfx) {
static lv_point_t valid_pos[] = {{0,0}, {LV_COORD_MIN, LV_COORD_MIN}};
tileview = lv_tileview_create(lv_scr_act(), NULL);
lv_tileview_set_valid_positions(tileview, valid_pos, 1);
lv_tileview_set_edge_flash(tileview, false);
tile1 = lv_obj_create(tileview, NULL);
lv_obj_set_pos(tile1, 0, 0);
lv_obj_set_size(tile1, LV_HOR_RES, LV_VER_RES);
lv_tileview_add_element(tileview, tile1);
btnm1 = lv_btnm_create(tile1, NULL);
lv_btnm_set_map(btnm1, btnm_map1);
lv_obj_set_size(btnm1, LV_HOR_RES, LV_VER_RES);
labelStyle = const_cast<lv_style_t *>(lv_label_get_style(btnm1, LV_BTNM_STYLE_BTN_REL));
labelStyle->text.font = &jetbrains_mono_bold_20;
labelStyle->body.grad_color = labelStyle->body.main_color;
lv_btnm_set_style(btnm1, LV_BTNM_STYLE_BTN_REL, labelStyle);
lv_btnm_set_style(btnm1, LV_BTNM_STYLE_BTN_PR, labelStyle);
lv_obj_align(btnm1, tile1, LV_ALIGN_CENTER, 0, 0);
btnm1->user_data = this;
lv_obj_set_event_cb(btnm1, event_handler);
/*
tile2 = lv_obj_create(tileview, NULL);
lv_obj_set_pos(tile2, 0, LV_VER_RES);
lv_obj_set_size(tile2, LV_HOR_RES, LV_VER_RES);
lv_tileview_add_element(tileview, tile2);
btnm2 = lv_btnm_create(tileview, NULL);
lv_btnm_set_map(btnm2, btnm_map2);
lv_obj_align(btnm2, tile2, LV_ALIGN_CENTER, 0, 0);
*/
/*
tile1 = lv_obj_create(tileview, NULL);
lv_obj_set_pos(tile1, 0, 0);
lv_obj_set_size(tile1, LV_HOR_RES, LV_VER_RES);
lv_tileview_add_element(tileview, tile1);
btn1 = lv_btn_create(tile1, NULL);
lv_obj_align(btn1, tile1, LV_ALIGN_CENTER, 0, 0);
label1 = lv_label_create(btn1, NULL);
lv_label_set_text(label1, "Button1");
*/
/*
tile2 = lv_obj_create(tileview, NULL);
lv_obj_set_pos(tile2, 0, LV_VER_RES);
lv_obj_set_size(tile2, LV_HOR_RES, LV_VER_RES);
lv_tileview_add_element(tileview, tile2);
btn2 = lv_btn_create(tile2, NULL);
lv_obj_align(btn2, tile2, LV_ALIGN_CENTER, 0, 0);
label2 = lv_label_create(btn2, NULL);
lv_label_set_text(label2, "Button2");
tile3 = lv_obj_create(tileview, NULL);
lv_obj_set_pos(tile3, 0, LV_VER_RES*2);
lv_obj_set_size(tile3, LV_HOR_RES, LV_VER_RES);
lv_tileview_add_element(tileview, tile3);
btn3 = lv_btn_create(tile3, NULL);
lv_obj_align(btn3, tile3, LV_ALIGN_CENTER, 0, 0);
label3 = lv_label_create(btn3, NULL);
lv_label_set_text(label3, "Button3");
*/
}
Tile::~Tile() {
lv_obj_clean(lv_scr_act());
}
void Tile::Refresh(bool fullRefresh) {
}
void Tile::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_CLICKED) {
NRF_LOG_INFO("Clicked");
nextScreen = Screen::NextScreen::App;
clickCount++;
}
else if(event == LV_EVENT_VALUE_CHANGED) {
NRF_LOG_INFO("Toggled");
}
}

@ -0,0 +1,56 @@
#pragma once
#include <cstdint>
#include <chrono>
#include <Components/Gfx/Gfx.h>
#include "Screen.h"
#include <bits/unique_ptr.h>
#include "../Fonts/lcdfont14.h"
#include "../Fonts/lcdfont70.h"
#include "../../Version.h"
#include <lvgl/src/lv_core/lv_style.h>
namespace Pinetime {
namespace Applications {
namespace Screens {
class Tile : public Screen {
public:
explicit Tile(DisplayApp* app, Components::Gfx& gfx);
~Tile() override;
void Refresh(bool fullRefresh) override;
void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
void OnButtonPushed() override {nextScreen = NextScreen::Clock;}
private:
const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data};
const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data};
lv_style_t* labelStyle;
lv_obj_t * label1;
lv_obj_t * label2;
lv_obj_t * label3;
lv_obj_t* backgroundLabel;
lv_obj_t * button;
lv_obj_t * labelClick;
lv_obj_t *tileview;
lv_obj_t * tile1;
lv_obj_t * tile2;
lv_obj_t * list;
lv_obj_t * list_btn;
lv_obj_t * tile3;
lv_obj_t * btn1;
lv_obj_t * btn2;
lv_obj_t * btn3;
lv_obj_t * btnm1;
lv_obj_t * btnm2;
uint32_t clickCount = 0 ;
uint32_t previousClickCount = 0;
};
}
}
}

@ -78,26 +78,26 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
info.action = action; info.action = action;
info.gesture = static_cast<Gestures>(touchData[gestureIndex]); info.gesture = static_cast<Gestures>(touchData[gestureIndex]);
NRF_LOG_INFO("---------------") // NRF_LOG_INFO("---------------")
NRF_LOG_INFO("ID : %d", pointId); // NRF_LOG_INFO("ID : %d", pointId);
NRF_LOG_INFO("NB : %d", nbTouchPoints); // NRF_LOG_INFO("NB : %d", nbTouchPoints);
NRF_LOG_INFO("X/Y :%d / %d", info.x, info.y); // NRF_LOG_INFO("X/Y :%d / %d", info.x, info.y);
NRF_LOG_INFO("Action : %d", action); // NRF_LOG_INFO("Action : %d", action);
NRF_LOG_INFO("Finger : %d", finger); // NRF_LOG_INFO("Finger : %d", finger);
NRF_LOG_INFO("Pressure : %d", pressure); // NRF_LOG_INFO("Pressure : %d", pressure);
NRF_LOG_INFO("area : %d", area); // NRF_LOG_INFO("area : %d", area);
NRF_LOG_INFO("Touch : %s", info.isTouch?"Yes" : "No"); // NRF_LOG_INFO("Touch : %s", info.isTouch?"Yes" : "No");
switch(info.gesture) {// gesture // switch(info.gesture) {// gesture
case Gestures::None: NRF_LOG_INFO("Gesture : None"); break; // case Gestures::None: NRF_LOG_INFO("Gesture : None"); break;
case Gestures::SlideDown: NRF_LOG_INFO("Gesture : Slide Down"); break; // case Gestures::SlideDown: NRF_LOG_INFO("Gesture : Slide Down"); break;
case Gestures::SlideUp: NRF_LOG_INFO("Gesture : Slide Up"); break; // case Gestures::SlideUp: NRF_LOG_INFO("Gesture : Slide Up"); break;
case Gestures::SlideLeft: NRF_LOG_INFO("Gesture : Slide Left"); break; // case Gestures::SlideLeft: NRF_LOG_INFO("Gesture : Slide Left"); break;
case Gestures::SlideRight: NRF_LOG_INFO("Gesture : Slide Right"); break; // case Gestures::SlideRight: NRF_LOG_INFO("Gesture : Slide Right"); break;
case Gestures::SingleTap: NRF_LOG_INFO("Gesture : Single click"); break; // case Gestures::SingleTap: NRF_LOG_INFO("Gesture : Single click"); break;
case Gestures::DoubleTap: NRF_LOG_INFO("Gesture : Double click"); break; // case Gestures::DoubleTap: NRF_LOG_INFO("Gesture : Double click"); break;
case Gestures::LongPress: NRF_LOG_INFO("Gesture : Long press"); break; // case Gestures::LongPress: NRF_LOG_INFO("Gesture : Long press"); break;
default : NRF_LOG_INFO("Unknown"); break; // default : NRF_LOG_INFO("Unknown"); break;
} // }
} }

@ -563,7 +563,7 @@ typedef void * lv_obj_user_data_t;
#define LV_USE_TILEVIEW 1 #define LV_USE_TILEVIEW 1
#if LV_USE_TILEVIEW #if LV_USE_TILEVIEW
/*Time of slide animation [ms] (0: no animation)*/ /*Time of slide animation [ms] (0: no animation)*/
# define LV_TILEVIEW_DEF_ANIM_TIME 300 # define LV_TILEVIEW_DEF_ANIM_TIME 0
#endif #endif
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ /*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/

@ -82,7 +82,7 @@ extern "C" {
void DebounceTimerCallback(TimerHandle_t xTimer) { void DebounceTimerCallback(TimerHandle_t xTimer) {
xTimerStop(xTimer, 0); xTimerStop(xTimer, 0);
if(isSleeping) { /*if(isSleeping) {
SystemTask_PushMessage(SystemTaskMessages::GoToRunning); SystemTask_PushMessage(SystemTaskMessages::GoToRunning);
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToRunning); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToRunning);
isSleeping = false; isSleeping = false;
@ -93,7 +93,8 @@ void DebounceTimerCallback(TimerHandle_t xTimer) {
SystemTask_PushMessage(SystemTaskMessages::GoToSleep); SystemTask_PushMessage(SystemTaskMessages::GoToSleep);
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep);
isSleeping = true; isSleeping = true;
} }*/
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::ButtonPushed);
} }
void SystemTask_PushMessage(SystemTaskMessages message) { void SystemTask_PushMessage(SystemTaskMessages message) {
@ -126,8 +127,9 @@ void SystemTask(void *) {
lcd.reset(new Pinetime::Drivers::St7789(*spi, pinLcdDataCommand)); lcd.reset(new Pinetime::Drivers::St7789(*spi, pinLcdDataCommand));
gfx.reset(new Pinetime::Components::Gfx(*lcd)); gfx.reset(new Pinetime::Components::Gfx(*lcd));
lvgl.reset(new Pinetime::Components::LittleVgl(*lcd));
touchPanel.reset(new Pinetime::Drivers::Cst816S()); touchPanel.reset(new Pinetime::Drivers::Cst816S());
lvgl.reset(new Pinetime::Components::LittleVgl(*lcd, *touchPanel));
ptrLcd = lcd.get(); ptrLcd = lcd.get();
spi->Init(); spi->Init();