mcu_hi3321_watch/middleware/services/gui/lvgl/sample/watch/watch.c
2025-05-26 20:15:20 +08:00

244 lines
8.6 KiB
C

/*
* Copyright (c) @CompanyNameMagicTag. 2023. All rights reserved.
*/
#include "watch.h"
#include "sys/time.h"
#include "lvgl.h"
#include "lv_demo_watch_font.h"
#if LV_USE_DEMO_WATCH
#define TIME_OBJ_WIDTH lv_disp_get_hor_res(_lv_refr_get_disp_refreshing())
#define TIME_OBJ_HEIGHT lv_disp_get_ver_res(_lv_refr_get_disp_refreshing()) / 3
typedef struct {
lv_obj_t* timeLabel;
lv_obj_t* dateLabel;
lv_obj_t* weekdayLabel;
} LvClock;
static bool g_isPressed = false;
static bool g_isAppListActive = false;
static lv_obj_t* g_appList = NULL;
#define MIN_TO_HOUR 60
#define HOURLY_SYSTEM 24
static LvPageInfo g_pageInfo;
static void ClockPreloadCb(lv_obj_t* obj)
{
LV_LOGI("callback %s func\n", __FUNCTION__);
}
static void ClockUnloadCb(lv_obj_t* obj)
{
LV_LOGI("callback %s func\n", __FUNCTION__);
}
static void ClockScrollBeginCb(lv_obj_t* obj, bool isActive)
{
LV_LOGI("callback[%s]: OBJ[%p] IsActive[%d]\n", __FUNCTION__, obj, isActive);
}
static void ClockScrollEndCb(lv_obj_t* obj, bool isActive)
{
LV_LOGI("callback[%s]: OBJ[%p] IsActive[%d]\n", __FUNCTION__, obj, isActive);
}
static void ClockCoverBeginCb(lv_obj_t* obj, bool isCovered)
{
LV_LOGI("callback[%s]: OBJ[%p] isCovered[%d]\n", __FUNCTION__, obj, isCovered);
}
static void ClockCoverEndCb(lv_obj_t* obj, bool isCovered)
{
LV_LOGI("callback[%s]: OBJ[%p] isCovered[%d]\n", __FUNCTION__, obj, isCovered);
}
LvPageInfo* GetClockPageInfo()
{
g_pageInfo.preload = ClockPreloadCb;
g_pageInfo.unload = ClockUnloadCb;
g_pageInfo.scrollBegin = ClockScrollBeginCb;
g_pageInfo.scrollEnd = ClockScrollEndCb;
g_pageInfo.coverBegin = ClockCoverBeginCb;
g_pageInfo.coverEnd = ClockCoverEndCb;
return &g_pageInfo;
}
static void ClockDateTaskCb(lv_timer_t* timer)
{
// 7: day count a week
static const char* weekDay[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
static time_t unixTime;
static struct tm* timeInfo;
struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t second = tv.tv_sec;
int minutes = second / MIN_TO_HOUR;
int hour = minutes / MIN_TO_HOUR;
int day = hour / HOURLY_SYSTEM;
int weekday = (day / 7) % 7; // 7: day to weekday
int realHour = hour % HOURLY_SYSTEM;
int realMinute = minutes % MIN_TO_HOUR;
int realMilliSecond = second % MIN_TO_HOUR;
int realDay = day % HOURLY_SYSTEM + 1;
if (timer != NULL && timer->user_data != NULL) {
LvClock* clock = (LvClock*)(timer->user_data);
if (clock->timeLabel != NULL) {
lv_label_set_text_fmt(clock->timeLabel, "%02d:%02d:%02d", realHour, realMinute, realMilliSecond);
lv_obj_align_to(clock->timeLabel, lv_obj_get_parent(clock->timeLabel), LV_ALIGN_CENTER, 0, 0);
}
if (clock->weekdayLabel != NULL) {
lv_label_set_text_fmt(clock->weekdayLabel, "%02d %s", realDay, weekDay[weekday]);
// -2: offset
lv_obj_align_to(clock->weekdayLabel, lv_obj_get_parent(clock->weekdayLabel), LV_ALIGN_BOTTOM_MID, -2, 0);
}
}
}
static lv_obj_t* CreateData(lv_obj_t* parent)
{
static lv_style_t dateStyle;
lv_style_init(&dateStyle);
lv_style_set_bg_opa(&dateStyle, LV_OPA_0);
lv_style_set_border_width(&dateStyle, 0);
lv_style_set_radius(&dateStyle, 5); // 5: radius
lv_style_set_bg_color(&dateStyle, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_pad_left(&dateStyle, 0);
lv_style_set_pad_right(&dateStyle, 0);
/* Date display */
lv_obj_t* dateObj = lv_obj_create(parent);
lv_obj_clear_flag(dateObj, LV_OBJ_FLAG_CLICKABLE);
lv_obj_clear_flag(dateObj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(dateObj, TIME_OBJ_WIDTH, TIME_OBJ_HEIGHT);
lv_obj_align_to(dateObj, parent, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_style(dateObj, &dateStyle, LV_STATE_DEFAULT);
return dateObj;
}
static lv_obj_t* CreateTime(lv_obj_t* parent)
{
static lv_style_t timeStyle;
lv_style_init(&timeStyle);
lv_style_set_bg_opa(&timeStyle, LV_OPA_0);
lv_style_set_border_width(&timeStyle, 0);
lv_style_set_radius(&timeStyle, 0);
lv_style_set_pad_all(&timeStyle, 0);
/* Time display */
lv_obj_t* timeObj = lv_obj_create(parent);
lv_obj_clear_flag(timeObj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_clear_flag(timeObj, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(timeObj, TIME_OBJ_WIDTH, TIME_OBJ_HEIGHT);
lv_obj_align_to(timeObj, parent, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_style(timeObj, &timeStyle, LV_STATE_DEFAULT);
return timeObj;
}
static lv_obj_t* CreateWatchBg(lv_obj_t* parent)
{
static lv_style_t dateTimeClockStyle;
lv_style_init(&dateTimeClockStyle);
lv_style_set_bg_opa(&dateTimeClockStyle, LV_OPA_COVER);
lv_style_set_border_width(&dateTimeClockStyle, 0);
lv_style_set_bg_color(&dateTimeClockStyle, lv_color_black());
lv_style_set_pad_left(&dateTimeClockStyle, 1);
lv_style_set_pad_right(&dateTimeClockStyle, 1);
lv_style_set_pad_top(&dateTimeClockStyle, 0);
lv_style_set_pad_bottom(&dateTimeClockStyle, 0);
/* Time & Date */
lv_obj_t* timeDateObj = lv_obj_create(parent);
lv_obj_clear_flag(timeDateObj, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_clear_flag(timeDateObj, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(timeDateObj, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL) * 3 / 5); // 3, 5: ratio
lv_obj_add_style(timeDateObj, &dateTimeClockStyle, LV_STATE_DEFAULT);
lv_obj_center(timeDateObj);
return timeDateObj;
}
static void ShowAppList(lv_obj_t* parent)
{
if (g_appList == NULL) {
g_appList = LvglPageMenuStart(parent);
} else {
lv_obj_clear_flag(g_appList, LV_OBJ_FLAG_HIDDEN);
SetBtnClickable(true);
}
}
static void EventClickCb(lv_event_t* e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* container = (lv_obj_t*)lv_event_get_user_data(e);
if (code == LV_EVENT_CLICKED) {
ShowAppList(container);
}
}
lv_obj_t* CreateListBtn(lv_obj_t* parent)
{
lv_obj_t* btn = lv_obj_create(parent);
lv_obj_clear_flag(btn, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(btn, LV_PCT(20), LV_PCT(20)); // 20: PCT
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btn, EventClickCb, LV_EVENT_ALL, parent);
lv_obj_set_style_bg_opa(btn, LV_OPA_0, 0);
lv_obj_set_style_border_opa(btn, LV_OPA_0, 0);
return btn;
}
void LvglCreateClock(lv_obj_t* subMenu)
{
/* Time font */
static lv_style_t timeLabelStyle;
lv_style_init(&timeLabelStyle);
lv_style_set_text_color(&timeLabelStyle, lv_color_white());
lv_style_set_text_font(&timeLabelStyle, GetLvFont(32)); // 32: size
lv_style_set_text_opa(&timeLabelStyle, LV_OPA_COVER);
lv_style_set_bg_opa(&timeLabelStyle, LV_OPA_0);
/* Date font */
static lv_style_t dateLabelStyle;
lv_style_init(&dateLabelStyle);
lv_style_set_text_opa(&dateLabelStyle, LV_OPA_COVER);
lv_style_set_bg_opa(&dateLabelStyle, LV_OPA_0);
lv_style_set_text_color(&dateLabelStyle, lv_color_white());
lv_style_set_text_font(&dateLabelStyle, GetLvFont(16)); // 16: size
/* Week font */
static lv_style_t weekLabelStyle;
lv_style_init(&weekLabelStyle);
lv_style_set_text_opa(&weekLabelStyle, LV_OPA_COVER);
lv_style_set_bg_opa(&weekLabelStyle, LV_OPA_0);
lv_style_set_text_color(&weekLabelStyle, lv_color_white());
lv_style_set_text_font(&weekLabelStyle, GetLvFont(16)); // 16: size
lv_obj_t* timeDateObj = CreateWatchBg(subMenu);
lv_obj_t* timeObj = CreateTime(timeDateObj);
lv_obj_t* dateObj = CreateData(timeDateObj);
lv_obj_t* btn = CreateListBtn(subMenu);
static LvClock lvClock = { 0 };
lvClock.timeLabel = lv_label_create(timeObj);
lv_obj_clear_flag(lvClock.timeLabel, LV_OBJ_FLAG_CLICKABLE);
lv_obj_clear_flag(lvClock.timeLabel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_style(lvClock.timeLabel, &timeLabelStyle, LV_STATE_DEFAULT);
/* Week display */
lvClock.weekdayLabel = lv_label_create(dateObj);
lv_obj_clear_flag(lvClock.weekdayLabel, LV_OBJ_FLAG_CLICKABLE);
lv_obj_clear_flag(lvClock.weekdayLabel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_style(lvClock.weekdayLabel, &weekLabelStyle, LV_STATE_DEFAULT);
lv_obj_align_to(lvClock.timeLabel, lv_obj_get_parent(lvClock.timeLabel), LV_ALIGN_CENTER, 0, 0);
lv_obj_align_to(lvClock.weekdayLabel, lvClock.timeLabel, LV_ALIGN_OUT_BOTTOM_MID, -2, 0); // -2: offset
lv_timer_create(ClockDateTaskCb, 200, (void*)&lvClock); // 200: period
}
#endif