LVGL 库提交

This commit is contained in:
2026-08-30 08:57:07 +08:00
parent 26c9098630
commit e2f199c6bf
1056 changed files with 556743 additions and 45 deletions
+503
View File
@@ -0,0 +1,503 @@
/**
* @file lv_calendar.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_calendar_private.h"
#include "../../draw/lv_draw_private.h"
#include "../../core/lv_obj_class_private.h"
#include "../../../lvgl.h"
#if LV_USE_CALENDAR
#include "../../misc/lv_assert.h"
/*********************
* DEFINES
*********************/
#define LV_CALENDAR_CTRL_TODAY LV_BUTTONMATRIX_CTRL_CUSTOM_1
#define LV_CALENDAR_CTRL_HIGHLIGHT LV_BUTTONMATRIX_CTRL_CUSTOM_2
#define MY_CLASS (&lv_calendar_class)
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_calendar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void draw_task_added_event_cb(lv_event_t * e);
static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day);
static uint8_t get_month_length(int32_t year, int32_t month);
static uint8_t is_leap_year(uint32_t year);
static void highlight_update(lv_obj_t * calendar);
#if LV_USE_CALENDAR_CHINESE
static lv_calendar_date_t gregorian_get_last_month_time(lv_calendar_date_t * time);
static lv_calendar_date_t gregorian_get_next_month_time(lv_calendar_date_t * time);
static void chinese_calendar_set_day_name(lv_obj_t * calendar, uint8_t index, uint8_t day,
lv_calendar_date_t * gregorian_time);
#endif
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_calendar_class = {
.constructor_cb = lv_calendar_constructor,
.width_def = (LV_DPI_DEF * 3) / 2,
.height_def = (LV_DPI_DEF * 3) / 2,
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
.instance_size = sizeof(lv_calendar_t),
.base_class = &lv_obj_class,
.name = "lv_calendar",
};
static const char * day_names_def[7] = LV_CALENDAR_DEFAULT_DAY_NAMES;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t * lv_calendar_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
/*=====================
* Setter functions
*====================*/
void lv_calendar_set_day_names(lv_obj_t * obj, const char * day_names[])
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
uint32_t i;
for(i = 0; i < 7; i++) {
calendar->map[i] = day_names[i];
}
lv_obj_invalidate(obj);
}
void lv_calendar_set_today_date(lv_obj_t * obj, uint32_t year, uint32_t month, uint32_t day)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
calendar->today.year = year;
calendar->today.month = month;
calendar->today.day = day;
highlight_update(obj);
}
void lv_calendar_set_highlighted_dates(lv_obj_t * obj, lv_calendar_date_t highlighted[], size_t date_num)
{
LV_ASSERT_NULL(highlighted);
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
calendar->highlighted_dates = highlighted;
calendar->highlighted_dates_num = date_num;
highlight_update(obj);
}
void lv_calendar_set_month_shown(lv_obj_t * obj, uint32_t year, uint32_t month)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
calendar->showed_date.year = year;
calendar->showed_date.month = month;
calendar->showed_date.day = 1;
lv_calendar_date_t d;
d.year = calendar->showed_date.year;
d.month = calendar->showed_date.month;
d.day = calendar->showed_date.day;
uint32_t i;
/*Remove the disabled state but revert it for day names*/
lv_buttonmatrix_clear_button_ctrl_all(calendar->btnm, LV_BUTTONMATRIX_CTRL_DISABLED);
for(i = 0; i < 7; i++) {
lv_buttonmatrix_set_button_ctrl(calendar->btnm, i, LV_BUTTONMATRIX_CTRL_DISABLED);
}
uint8_t act_mo_len = get_month_length(d.year, d.month);
uint8_t day_first = get_day_of_week(d.year, d.month, 1);
uint8_t c;
#if LV_USE_CALENDAR_CHINESE
lv_calendar_date_t gregorian_time;
gregorian_time = d;
#endif
for(i = day_first, c = 1; i < act_mo_len + day_first; i++, c++) {
#if LV_USE_CALENDAR_CHINESE
if(calendar->use_chinese_calendar) {
gregorian_time.day = c;
chinese_calendar_set_day_name(obj, i, c, &gregorian_time);
}
else
#endif
lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
}
uint8_t prev_mo_len = get_month_length(d.year, d.month - 1);
#if LV_USE_CALENDAR_CHINESE
gregorian_time = gregorian_get_last_month_time(&d);
#endif
for(i = 0, c = prev_mo_len - day_first + 1; i < day_first; i++, c++) {
#if LV_USE_CALENDAR_CHINESE
if(calendar->use_chinese_calendar) {
gregorian_time.day = c;
chinese_calendar_set_day_name(obj, i, c, &gregorian_time);
}
else
#endif
lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
lv_buttonmatrix_set_button_ctrl(calendar->btnm, i + 7, LV_BUTTONMATRIX_CTRL_DISABLED);
}
#if LV_USE_CALENDAR_CHINESE
gregorian_time = gregorian_get_next_month_time(&d);
#endif
for(i = day_first + act_mo_len, c = 1; i < 6 * 7; i++, c++) {
#if LV_USE_CALENDAR_CHINESE
if(calendar->use_chinese_calendar) {
gregorian_time.day = c;
chinese_calendar_set_day_name(obj, i, c, &gregorian_time);
}
else
#endif
lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
lv_buttonmatrix_set_button_ctrl(calendar->btnm, i + 7, LV_BUTTONMATRIX_CTRL_DISABLED);
}
highlight_update(obj);
/*Reset the focused button if the days changes*/
if(lv_buttonmatrix_get_selected_button(calendar->btnm) != LV_BUTTONMATRIX_BUTTON_NONE) {
lv_buttonmatrix_set_selected_button(calendar->btnm, day_first + 7);
}
lv_obj_invalidate(obj);
/* The children of the calendar are probably headers.
* Notify them to let the headers updated to the new date*/
uint32_t child_cnt = lv_obj_get_child_count(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
if(child == calendar->btnm) continue;
lv_obj_send_event(child, LV_EVENT_VALUE_CHANGED, obj);
}
}
/*=====================
* Getter functions
*====================*/
lv_obj_t * lv_calendar_get_btnmatrix(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
const lv_calendar_t * calendar = (lv_calendar_t *)obj;
return calendar->btnm;
}
const lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
const lv_calendar_t * calendar = (lv_calendar_t *)obj;
return &calendar->today;
}
const lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
const lv_calendar_t * calendar = (lv_calendar_t *)obj;
return &calendar->showed_date;
}
lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
return calendar->highlighted_dates;
}
size_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
return calendar->highlighted_dates_num;
}
lv_result_t lv_calendar_get_pressed_date(const lv_obj_t * obj, lv_calendar_date_t * date)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
uint32_t d = lv_buttonmatrix_get_selected_button(calendar->btnm);
if(d == LV_BUTTONMATRIX_BUTTON_NONE) {
date->year = 0;
date->month = 0;
date->day = 0;
return LV_RESULT_INVALID;
}
const char * txt = lv_buttonmatrix_get_button_text(calendar->btnm, lv_buttonmatrix_get_selected_button(calendar->btnm));
if(txt[1] == 0) date->day = txt[0] - '0';
else date->day = (txt[0] - '0') * 10 + (txt[1] - '0');
date->year = calendar->showed_date.year;
date->month = calendar->showed_date.month;
return LV_RESULT_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_calendar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_calendar_t * calendar = (lv_calendar_t *)obj;
/*Initialize the allocated 'ext'*/
calendar->today.year = 2024;
calendar->today.month = 1;
calendar->today.day = 1;
calendar->showed_date.year = 2024;
calendar->showed_date.month = 1;
calendar->showed_date.day = 1;
calendar->highlighted_dates = NULL;
calendar->highlighted_dates_num = 0;
lv_memzero(calendar->nums, sizeof(calendar->nums));
uint8_t i;
uint8_t j = 0;
for(i = 0; i < 8 * 7; i++) {
/*Every 8th string is "\n"*/
if(i != 0 && (i + 1) % 8 == 0) {
calendar->map[i] = "\n";
}
else if(i < 7) {
calendar->map[i] = day_names_def[i];
}
else {
calendar->nums[j][0] = 'x';
calendar->map[i] = calendar->nums[j];
j++;
}
}
calendar->map[8 * 7 - 1] = "";
calendar->btnm = lv_buttonmatrix_create(obj);
lv_buttonmatrix_set_map(calendar->btnm, calendar->map);
lv_buttonmatrix_set_button_ctrl_all(calendar->btnm, LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_NO_REPEAT);
lv_obj_add_event_cb(calendar->btnm, draw_task_added_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_set_width(calendar->btnm, lv_pct(100));
lv_obj_add_flag(calendar->btnm, LV_OBJ_FLAG_EVENT_BUBBLE | LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_grow(calendar->btnm, 1);
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
lv_calendar_set_month_shown(obj, calendar->showed_date.year, calendar->showed_date.month);
lv_calendar_set_today_date(obj, calendar->today.year, calendar->today.month, calendar->today.day);
}
static void draw_task_added_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_current_target(e);
lv_draw_task_t * draw_task = lv_event_get_param(e);
if(((lv_draw_dsc_base_t *)draw_task->draw_dsc)->part != LV_PART_ITEMS) return;
lv_draw_fill_dsc_t * fill_draw_dsc = lv_draw_task_get_fill_dsc(draw_task);
lv_draw_border_dsc_t * border_draw_dsc = lv_draw_task_get_border_dsc(draw_task);
if(!fill_draw_dsc && !border_draw_dsc) {
return;
}
int32_t id = ((lv_draw_dsc_base_t *)draw_task->draw_dsc)->id1;
/*Day name styles*/
if(id < 7) {
if(fill_draw_dsc) fill_draw_dsc->opa = LV_OPA_TRANSP;
if(border_draw_dsc) border_draw_dsc->opa = LV_OPA_TRANSP;
}
else if(lv_buttonmatrix_has_button_ctrl(obj, id, LV_BUTTONMATRIX_CTRL_DISABLED)) {
if(fill_draw_dsc) fill_draw_dsc->opa = LV_OPA_TRANSP;
if(border_draw_dsc) border_draw_dsc->opa = LV_OPA_TRANSP;
}
if(lv_buttonmatrix_has_button_ctrl(obj, id, LV_CALENDAR_CTRL_HIGHLIGHT)) {
if(border_draw_dsc) border_draw_dsc->color = lv_theme_get_color_primary(obj);
if(fill_draw_dsc) fill_draw_dsc->opa = LV_OPA_40;
if(fill_draw_dsc) fill_draw_dsc->color = lv_theme_get_color_primary(obj);
if(lv_buttonmatrix_get_selected_button(obj) == (uint32_t)id) {
if(fill_draw_dsc) fill_draw_dsc->opa = LV_OPA_70;
}
}
if(lv_buttonmatrix_has_button_ctrl(obj, id, LV_CALENDAR_CTRL_TODAY)) {
if(border_draw_dsc) border_draw_dsc->opa = LV_OPA_COVER;
if(border_draw_dsc) border_draw_dsc->color = lv_theme_get_color_primary(obj);
if(border_draw_dsc) border_draw_dsc->width += 1;
}
}
/**
* Get the number of days in a month
* @param year a year
* @param month a month. The range is basically [1..12] but [-11..0] or [13..24] is also
* supported to handle next/prev. year
* @return [28..31]
*/
static uint8_t get_month_length(int32_t year, int32_t month)
{
month--;
if(month < 0) {
year--; /*Already in the previous year (won't be less than -12 to skip a whole year)*/
month = 12 + month; /*`month` is negative, the result will be < 12*/
}
if(month >= 12) {
year++;
month -= 12;
}
/*month == 1 is february*/
return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2;
}
/**
* Tells whether a year is leap year or not
* @param year a year
* @return 0: not leap year; 1: leap year
*/
static uint8_t is_leap_year(uint32_t year)
{
return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1;
}
/**
* Get the day of the week
* @param year a year
* @param month a month [1..12]
* @param day a day [1..32]
* @return [0..6] which means [Sun..Sat] or [Mon..Sun] depending on LV_CALENDAR_WEEK_STARTS_MONDAY
*/
static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day)
{
uint32_t a = month < 3 ? 1 : 0;
uint32_t b = year - a;
#if LV_CALENDAR_WEEK_STARTS_MONDAY
uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400) - 1) % 7;
#else
uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400)) % 7;
#endif
return day_of_week ;
}
static void highlight_update(lv_obj_t * obj)
{
lv_calendar_t * calendar = (lv_calendar_t *)obj;
uint32_t i;
/*Clear all kind of selection*/
lv_buttonmatrix_clear_button_ctrl_all(calendar->btnm, LV_CALENDAR_CTRL_TODAY | LV_CALENDAR_CTRL_HIGHLIGHT);
uint8_t day_first = get_day_of_week(calendar->showed_date.year, calendar->showed_date.month, 1);
if(calendar->highlighted_dates) {
for(i = 0; i < calendar->highlighted_dates_num; i++) {
if(calendar->highlighted_dates[i].year == calendar->showed_date.year &&
calendar->highlighted_dates[i].month == calendar->showed_date.month) {
lv_buttonmatrix_set_button_ctrl(calendar->btnm, calendar->highlighted_dates[i].day - 1 + day_first + 7,
LV_CALENDAR_CTRL_HIGHLIGHT);
}
}
}
if(calendar->showed_date.year == calendar->today.year && calendar->showed_date.month == calendar->today.month) {
lv_buttonmatrix_set_button_ctrl(calendar->btnm, calendar->today.day - 1 + day_first + 7, LV_CALENDAR_CTRL_TODAY);
}
}
#if LV_USE_CALENDAR_CHINESE
static lv_calendar_date_t gregorian_get_last_month_time(lv_calendar_date_t * time)
{
lv_calendar_date_t last_month_time;
if(time->month == 1) {
last_month_time.month = 12;
last_month_time.year = time->year - 1;
}
else {
last_month_time.month = time->month - 1;
last_month_time.year = time->year;
}
return last_month_time;
}
static lv_calendar_date_t gregorian_get_next_month_time(lv_calendar_date_t * time)
{
lv_calendar_date_t next_month_time;
if(time->month == 12) {
next_month_time.month = 1;
next_month_time.year = time->year + 1;
}
else {
next_month_time.month = time->month + 1;
next_month_time.year = time->year;
}
return next_month_time;
}
static void chinese_calendar_set_day_name(lv_obj_t * obj, uint8_t index, uint8_t day,
lv_calendar_date_t * gregorian_time)
{
lv_calendar_t * calendar = (lv_calendar_t *)obj;
const char * day_name = lv_calendar_get_day_name(gregorian_time);
if(day_name != NULL)
lv_snprintf(calendar->nums[index], sizeof(calendar->nums[0]),
"%d\n%s",
day,
day_name);
else
lv_snprintf(calendar->nums[index], sizeof(calendar->nums[0]), "%d", day);
}
#endif
#endif /*LV_USE_CALENDAR*/
+160
View File
@@ -0,0 +1,160 @@
/**
* @file lv_calendar.h
*
*/
#ifndef LV_CALENDAR_H
#define LV_CALENDAR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../buttonmatrix/lv_buttonmatrix.h"
#if LV_USE_CALENDAR
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**
* Represents a date on the calendar object (platform-agnostic).
*/
typedef struct {
uint16_t year;
int8_t month; /**< 1..12 */
int8_t day; /**< 1..31 */
} lv_calendar_date_t;
LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_calendar_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a calendar widget
* @param parent pointer to an object, it will be the parent of the new calendar
* @return pointer the created calendar
*/
lv_obj_t * lv_calendar_create(lv_obj_t * parent);
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/**
* Set the today's date
* @param obj pointer to a calendar object
* @param year today's year
* @param month today's month [1..12]
* @param day today's day [1..31]
*/
void lv_calendar_set_today_date(lv_obj_t * obj, uint32_t year, uint32_t month, uint32_t day);
/**
* Set the currently showed
* @param obj pointer to a calendar object
* @param year today's year
* @param month today's month [1..12]
*/
void lv_calendar_set_month_shown(lv_obj_t * obj, uint32_t year, uint32_t month);
/**
* Set the highlighted dates
* @param obj pointer to a calendar object
* @param highlighted pointer to an `lv_calendar_date_t` array containing the dates.
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
* @param date_num number of dates in the array
*/
void lv_calendar_set_highlighted_dates(lv_obj_t * obj, lv_calendar_date_t highlighted[], size_t date_num);
/**
* Set the name of the days
* @param obj pointer to a calendar object
* @param day_names pointer to an array with the names.
* E.g. `const char * days[7] = {"Sun", "Mon", ...}`
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
*/
void lv_calendar_set_day_names(lv_obj_t * obj, const char ** day_names);
/*=====================
* Getter functions
*====================*/
/**
* Get the button matrix object of the calendar.
* It shows the dates and day names.
* @param obj pointer to a calendar object
* @return pointer to a the button matrix
*/
lv_obj_t * lv_calendar_get_btnmatrix(const lv_obj_t * obj);
/**
* Get the today's date
* @param calendar pointer to a calendar object
* @return return pointer to an `lv_calendar_date_t` variable containing the date of today.
*/
const lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar);
/**
* Get the currently showed
* @param calendar pointer to a calendar object
* @return pointer to an `lv_calendar_date_t` variable containing the date is being shown.
*/
const lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar);
/**
* Get the highlighted dates
* @param calendar pointer to a calendar object
* @return pointer to an `lv_calendar_date_t` array containing the dates.
*/
lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar);
/**
* Get the number of the highlighted dates
* @param calendar pointer to a calendar object
* @return number of highlighted days
*/
size_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar);
/**
* Get the currently pressed day
* @param calendar pointer to a calendar object
* @param date store the pressed date here
* @return LV_RESULT_OK: there is a valid pressed date
* LV_RESULT_INVALID: there is no pressed data
*/
lv_result_t lv_calendar_get_pressed_date(const lv_obj_t * calendar, lv_calendar_date_t * date);
/*=====================
* Other functions
*====================*/
/**********************
* MACROS
**********************/
#include "lv_calendar_header_arrow.h"
#include "lv_calendar_header_dropdown.h"
#include "lv_calendar_chinese.h"
#endif /*LV_USE_CALENDAR*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_CALENDAR_H*/
@@ -0,0 +1,285 @@
/**
* @file lv_calendar_chinese.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_calendar_private.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_CHINESE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
const char festival_name[20];
uint8_t month;
uint8_t day;
} lv_calendar_festival_t;
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static const uint32_t calendar_chinese_table[199] = {/*1901-2099*/
0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A, /*1901-1910*/
0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754, /*1911-1920*/
0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E, /*1921-1930*/
0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48, /*1931-1940*/
0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51, /*1941-1950*/
0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C, /*1951-1960*/
0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46, /*1961-1970*/
0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50, /*1971-1980*/
0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x093746, 0x5497BB, /*1981-1990*/
0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645, /*1991-2000*/
0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E, /*2001-2010*/
0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9, /*2011-2020*/
0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x69573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43, /*2021-2030*/
0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C, /*2031-2040*/
0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37, /*2041-2050*/
0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06B244, 0x4AB638, 0x0AAE4C, 0x092E42, /*2051-2060*/
0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B, /*2061-2070*/
0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6, /*2071-2080*/
0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E, /*2081-2090*/
0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5 /*2091-2099*/
};
static const uint16_t month_total_day[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
static const char * chinese_calendar_month_name[] = {"正月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "十一月", "腊月"
};
static const char * chinese_calendar_leep_month_name[] = {"闰正月", "闰二月", "闰三月", "闰四月", "闰五月", "闰六月",
"闰七月", "闰八月", "闰九月", "闰十月", "闰十一月", "闰腊月"
};
static const char * chinese_calendar_day_name[] = {"初一", "初二", "初三", "初四", "初五",
"初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五",
"十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五",
"廿六", "廿七", "廿八", "廿九", "三十"
};
static const lv_calendar_festival_t festivals_base_chinese[] = {
{"春节", 1, 1},
{"元宵节", 1, 15},
{"端午节", 5, 5},
{"七夕节", 7, 7},
{"中元节", 7, 15},
{"中秋节", 8, 15},
{"重阳节", 9, 9},
{"腊八节", 12, 8},
{"除夕", 12, 29},/* To determine whether it is 12.29 or 12.30. */
{"除夕", 12, 30},/* To determine whether it is 12.29 or 12.30. */
};
static const lv_calendar_festival_t festivals_base_gregorian[] = {
{"元旦", 1, 1},
{"情人节", 2, 14},
{"妇女节", 3, 8},
{"植树节", 3, 12},
{"消费节", 3, 15},
{"愚人节", 4, 1},
{"劳动节", 5, 1},
{"青年节", 5, 4},
{"儿童节", 6, 1},
{"建党节", 7, 1},
{"建军节", 8, 1},
{"教师节", 9, 10},
{"国庆节", 10, 1},
{"万圣节", 10, 31},
{"平安夜", 12, 24},
{"圣诞节", 12, 25},
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_calendar_set_chinese_mode(lv_obj_t * obj, bool en)
{
lv_calendar_t * calendar = (lv_calendar_t *)obj;
calendar->use_chinese_calendar = en;
lv_calendar_set_month_shown(obj, calendar->today.year, calendar->today.month);
}
const char * lv_calendar_get_day_name(lv_calendar_date_t * gregorian)
{
uint16_t i, len;
lv_calendar_chinese_t chinese_calendar;
lv_calendar_gregorian_to_chinese(gregorian, &chinese_calendar);
if(gregorian->year > 2099 || gregorian->year < 1901)
return NULL;
len = sizeof(festivals_base_chinese) / sizeof(lv_calendar_festival_t);
for(i = 0; i < len; i++) {
if((chinese_calendar.today.month == festivals_base_chinese[i].month) &&
(chinese_calendar.today.day == festivals_base_chinese[i].day) &&
chinese_calendar.leep_month == false) {
if(chinese_calendar.today.month == 12 && chinese_calendar.today.day == 29) {
if((calendar_chinese_table[chinese_calendar.today.year - 1901] & 0xf00000) != 0) {
if((calendar_chinese_table[chinese_calendar.today.year - 1901] & 0x000080) == 0) {
return festivals_base_chinese[i].festival_name;
}
}
else {
if((calendar_chinese_table[chinese_calendar.today.year - 1901] & 0x000100) == 0) {
return festivals_base_chinese[i].festival_name;
}
}
}
else {
return festivals_base_chinese[i].festival_name;
}
}
}
len = sizeof(festivals_base_gregorian) / sizeof(lv_calendar_festival_t);
for(i = 0; i < len; i++) {
if((gregorian->month == festivals_base_gregorian[i].month) &&
(gregorian->day == festivals_base_gregorian[i].day))
return festivals_base_gregorian[i].festival_name;
}
if(chinese_calendar.today.day == 1) {
if(chinese_calendar.leep_month == false)
return chinese_calendar_month_name[chinese_calendar.today.month - 1];
else {
return chinese_calendar_leep_month_name[chinese_calendar.today.month - 1];
}
}
return (char *)chinese_calendar_day_name[chinese_calendar.today.day - 1];
}
void lv_calendar_gregorian_to_chinese(lv_calendar_date_t * gregorian_time, lv_calendar_chinese_t * chinese_time)
{
uint16_t year = gregorian_time->year;
uint8_t month = gregorian_time->month;
uint8_t day = gregorian_time->day;
/*Record the number of days between the Spring Festival
and the New Year's Day of that year.*/
uint16_t by_spring;
/*Record the number of days from the gregorian calendar
to the New Year's Day of that year.*/
uint16_t by_gregorian;
/*Record the number of days in that month*/
uint8_t days_per_month;
/*Record from which month the calculation starts.*/
uint8_t index;
bool leep_month;
if(year < 1901 || year > 2099) {
chinese_time->leep_month = 0;
chinese_time->today.year = 2000;
chinese_time->today.month = 1;
chinese_time->today.day = 1;
return;
}
if(((calendar_chinese_table[year - 1901] & 0x0060) >> 5) == 1)
by_spring = (calendar_chinese_table[year - 1901] & 0x001F) - 1;
else
by_spring = (calendar_chinese_table[year - 1901] & 0x001F) - 1 + 31;
by_gregorian = month_total_day[month - 1] + day - 1;
if((!(year % 4)) && (month > 2))
by_gregorian++;
if(by_gregorian >= by_spring) {/*Gregorian calendar days after the Spring Festival*/
by_gregorian -= by_spring;
month = 1;
index = 1;
leep_month = false;
if((calendar_chinese_table[year - 1901] & (0x80000 >> (index - 1))) == 0)
days_per_month = 29;
else
days_per_month = 30;
while(by_gregorian >= days_per_month) {
by_gregorian -= days_per_month;
index++;
if(month == ((calendar_chinese_table[year - 1901] & 0xF00000) >> 20)) {
leep_month = !leep_month;
if(leep_month == false)
month++;
}
else
month++;
if((calendar_chinese_table[year - 1901] & (0x80000 >> (index - 1))) == 0)
days_per_month = 29;
else
days_per_month = 30;
}
day = by_gregorian + 1;
}
else {/*Solar day before the Spring Festival*/
by_spring -= by_gregorian;
year--;
month = 12;
if(((calendar_chinese_table[year - 1901] & 0xF00000) >> 20) == 0)
index = 12;
else
index = 13;
leep_month = false;
if((calendar_chinese_table[year - 1901] & (0x80000 >> (index - 1))) == 0)
days_per_month = 29;
else
days_per_month = 30;
while(by_spring > days_per_month) {
by_spring -= days_per_month;
index--;
if(leep_month == false)
month--;
if(month == ((calendar_chinese_table[year - 1901] & 0xF00000) >> 20))
leep_month = !leep_month;
if((calendar_chinese_table[year - 1901] & (0x80000 >> (index - 1))) == 0)
days_per_month = 29;
else
days_per_month = 30;
}
day = days_per_month - by_spring + 1;
}
chinese_time->today.day = day;
chinese_time->today.month = month;
chinese_time->today.year = year;
chinese_time->leep_month = leep_month;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_CALENDAR_CHINESE*/
@@ -0,0 +1,68 @@
/**
* @file lv_calendar_chinese.h
*
*/
#ifndef LV_CALENDAR_CHINESE_H
#define LV_CALENDAR_CHINESE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj.h"
#include "lv_calendar.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_CHINESE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_calendar_date_t today;
bool leep_month;
} lv_calendar_chinese_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Enable the chinese calendar.
* @param obj pointer to a calendar object.
* @param en true: enable chinese calendar; false: disable
*/
void lv_calendar_set_chinese_mode(lv_obj_t * obj, bool en);
/**
* Get the name of the day
* @param gregorian to obtain the gregorian time for the name
* @return return the name of the day
*/
const char * lv_calendar_get_day_name(lv_calendar_date_t * gregorian);
/**
* Get the chinese time of the gregorian time (reference: https://www.cnblogs.com/liyang31tg/p/4123171.html)
* @param gregorian_time need to convert to chinese time in gregorian time
* @param chinese_time the chinese time convert from gregorian time
*/
void lv_calendar_gregorian_to_chinese(lv_calendar_date_t * gregorian_time, lv_calendar_chinese_t * chinese_time);
/**********************
* MACROS
**********************/
#endif /*LV_USE_CALENDAR_CHINESE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_CALENDAR_CHINESE_H*/
@@ -0,0 +1,158 @@
/**
* @file lv_calendar_header_arrow.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj_class_private.h"
#include "lv_calendar_header_arrow.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_HEADER_ARROW
#include "lv_calendar.h"
#include "../button/lv_button.h"
#include "../label/lv_label.h"
#include "../../layouts/flex/lv_flex.h"
#include "../../misc/lv_assert.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void month_event_cb(lv_event_t * e);
static void value_changed_event_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_calendar_header_arrow_class = {
.base_class = &lv_obj_class,
.constructor_cb = my_constructor,
.width_def = LV_PCT(100),
.height_def = LV_DPI_DEF / 3,
.name = "lv_calendar_header_arrow",
};
static const char * month_names_def[12] = LV_CALENDAR_DEFAULT_MONTH_NAMES;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t * lv_calendar_add_header_arrow(lv_obj_t * parent)
{
lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_arrow_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_TRACE_OBJ_CREATE("begin");
LV_UNUSED(class_p);
lv_obj_move_to_index(obj, 0);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START);
lv_obj_t * mo_prev = lv_button_create(obj);
lv_obj_set_style_bg_image_src(mo_prev, LV_SYMBOL_LEFT, 0);
lv_obj_set_height(mo_prev, lv_pct(100));
lv_obj_update_layout(mo_prev);
int32_t btn_size = lv_obj_get_height(mo_prev);
lv_obj_set_width(mo_prev, btn_size);
lv_obj_add_event_cb(mo_prev, month_event_cb, LV_EVENT_CLICKED, NULL);
lv_obj_remove_flag(mo_prev, LV_OBJ_FLAG_CLICK_FOCUSABLE);
lv_obj_t * label = lv_label_create(obj);
lv_label_set_long_mode(label, LV_LABEL_LONG_MODE_SCROLL_CIRCULAR);
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_set_flex_grow(label, 1);
lv_obj_t * mo_next = lv_button_create(obj);
lv_obj_set_style_bg_image_src(mo_next, LV_SYMBOL_RIGHT, 0);
lv_obj_set_size(mo_next, btn_size, btn_size);
lv_obj_add_event_cb(mo_next, month_event_cb, LV_EVENT_CLICKED, NULL);
lv_obj_remove_flag(mo_next, LV_OBJ_FLAG_CLICK_FOCUSABLE);
lv_obj_add_event_cb(obj, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
/*Refresh the drop downs*/
lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
}
static void month_event_cb(lv_event_t * e)
{
lv_obj_t * btn = lv_event_get_current_target(e);
lv_obj_t * header = lv_obj_get_parent(btn);
lv_obj_t * calendar = lv_obj_get_parent(header);
const lv_calendar_date_t * d;
d = lv_calendar_get_showed_date(calendar);
lv_calendar_date_t newd = *d;
LV_ASSERT_FORMAT_MSG(newd.month >= 1 && newd.month <= 12,
"Invalid month: %d (expected 1-12)", newd.month);
/*The last child is the right button*/
if(lv_obj_get_child(header, 0) == btn) {
if(newd.month == 1) {
newd.month = 12;
newd.year --;
}
else {
newd.month --;
}
}
else {
if(newd.month == 12) {
newd.month = 1;
newd.year ++;
}
else {
newd.month ++;
}
}
lv_calendar_set_month_shown(calendar, newd.year, newd.month);
lv_obj_t * label = lv_obj_get_child(header, 1);
lv_label_set_text_fmt(label, "%d %s", newd.year, month_names_def[newd.month - 1]);
}
static void value_changed_event_cb(lv_event_t * e)
{
lv_obj_t * header = lv_event_get_current_target(e);
lv_obj_t * calendar = lv_obj_get_parent(header);
const lv_calendar_date_t * date = lv_calendar_get_showed_date(calendar);
LV_ASSERT_FORMAT_MSG(date->month >= 1 && date->month <= 12,
"Invalid month: %d (expected 1-12)", date->month);
lv_obj_t * label = lv_obj_get_child(header, 1);
lv_label_set_text_fmt(label, "%d %s", date->year, month_names_def[date->month - 1]);
}
#endif /*LV_USE_CALENDAR_HEADER_ARROW*/
@@ -0,0 +1,49 @@
/**
* @file lv_calendar_header_arrow.h
*
*/
#ifndef LV_CALENDAR_HEADER_ARROW_H
#define LV_CALENDAR_HEADER_ARROW_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_HEADER_ARROW
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_calendar_header_arrow_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a calendar header with drop-drowns to select the year and month
* @param parent pointer to a calendar object.
* @return the created header
*/
lv_obj_t * lv_calendar_add_header_arrow(lv_obj_t * parent);
/**********************
* MACROS
**********************/
#endif /*LV_USE_CALENDAR_HEADER_ARROW*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_CALENDAR_HEADER_ARROW_H*/
@@ -0,0 +1,182 @@
/**
* @file lv_calendar_obj_dropdown.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj_class_private.h"
#include "lv_calendar_header_dropdown.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_HEADER_DROPDOWN
#include "lv_calendar.h"
#include "../dropdown/lv_dropdown.h"
#include "../../layouts/flex/lv_flex.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void year_event_cb(lv_event_t * e);
static void month_event_cb(lv_event_t * e);
static void value_changed_event_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_calendar_header_dropdown_class = {
.base_class = &lv_obj_class,
.width_def = LV_PCT(100),
.height_def = LV_SIZE_CONTENT,
.constructor_cb = my_constructor,
.name = "lv_calendar_header_dropdown",
};
static const char * month_list = "01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12";
static const char * year_list = {
"2025\n2024\n2023\n2022\n2021\n"
"2020\n2019\n2018\n2017\n2016\n2015\n2014\n2013\n2012\n2011\n2010\n2009\n2008\n2007\n2006\n2005\n2004\n2003\n2002\n2001\n"
"2000\n1999\n1998\n1997\n1996\n1995\n1994\n1993\n1992\n1991\n1990\n1989\n1988\n1987\n1986\n1985\n1984\n1983\n1982\n1981\n"
"1980\n1979\n1978\n1977\n1976\n1975\n1974\n1973\n1972\n1971\n1970\n1969\n1968\n1967\n1966\n1965\n1964\n1963\n1962\n1961\n"
"1960\n1959\n1958\n1957\n1956\n1955\n1954\n1953\n1952\n1951\n1950\n1949\n1948\n1947\n1946\n1945\n1944\n1943\n1942\n1941\n"
"1940\n1939\n1938\n1937\n1936\n1935\n1934\n1933\n1932\n1931\n1930\n1929\n1928\n1927\n1926\n1925\n1924\n1923\n1922\n1921\n"
"1920\n1919\n1918\n1917\n1916\n1915\n1914\n1913\n1912\n1911\n1910\n1909\n1908\n1907\n1906\n1905\n1904\n1903\n1902\n1901"
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t * lv_calendar_add_header_dropdown(lv_obj_t * parent)
{
lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_dropdown_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
void lv_calendar_header_dropdown_set_year_list(lv_obj_t * parent, const char * years_list)
{
/* Search for the header dropdown */
lv_obj_t * header = lv_obj_get_child_by_type(parent, 0, &lv_calendar_header_dropdown_class);
if(NULL == header) {
/* Header not found */
return;
}
/* Search for the year dropdown
* Index is 0 because in the header dropdown constructor the year dropdown (year_dd)
* is the first created child of the header */
const int32_t year_dropdown_index = 0;
lv_obj_t * year_dropdown = lv_obj_get_child_by_type(header, year_dropdown_index, &lv_dropdown_class);
if(NULL == year_dropdown) {
/* year dropdown not found */
return;
}
lv_dropdown_clear_options(year_dropdown);
lv_dropdown_set_options(year_dropdown, years_list);
lv_obj_invalidate(parent);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_TRACE_OBJ_CREATE("begin");
LV_UNUSED(class_p);
lv_obj_t * calendar = lv_obj_get_parent(obj);
lv_obj_move_to_index(obj, 0);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_obj_t * year_dd = lv_dropdown_create(obj);
lv_dropdown_set_options(year_dd, year_list);
lv_obj_add_event_cb(year_dd, year_event_cb, LV_EVENT_VALUE_CHANGED, calendar);
lv_obj_set_flex_grow(year_dd, 1);
lv_obj_t * month_dd = lv_dropdown_create(obj);
lv_dropdown_set_options(month_dd, month_list);
lv_obj_add_event_cb(month_dd, month_event_cb, LV_EVENT_VALUE_CHANGED, calendar);
lv_obj_set_flex_grow(month_dd, 1);
lv_obj_add_event_cb(obj, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
/*Refresh the drop downs*/
lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
}
static void month_event_cb(lv_event_t * e)
{
lv_obj_t * dropdown = lv_event_get_current_target(e);
lv_obj_t * calendar = lv_event_get_user_data(e);
uint32_t sel = lv_dropdown_get_selected(dropdown);
const lv_calendar_date_t * d;
d = lv_calendar_get_showed_date(calendar);
lv_calendar_date_t newd = *d;
newd.month = sel + 1;
lv_calendar_set_month_shown(calendar, newd.year, newd.month);
}
static void year_event_cb(lv_event_t * e)
{
lv_obj_t * dropdown = lv_event_get_current_target(e);
lv_obj_t * calendar = lv_event_get_user_data(e);
uint32_t sel = lv_dropdown_get_selected(dropdown);
const char * year_p = lv_dropdown_get_options(dropdown);
LV_ASSERT(3 + sel * 5 < lv_strlen(year_p));
/* NOTE: Assumes YYYY format */
const uint32_t year = (year_p[0 + sel * 5] - '0') * 1000 +
(year_p[1 + sel * 5] - '0') * 100 +
(year_p[2 + sel * 5] - '0') * 10 +
(year_p[3 + sel * 5] - '0');
const lv_calendar_date_t * d;
d = lv_calendar_get_showed_date(calendar);
lv_calendar_date_t newd = *d;
newd.year = year;
lv_calendar_set_month_shown(calendar, newd.year, newd.month);
}
static void value_changed_event_cb(lv_event_t * e)
{
lv_obj_t * header = lv_event_get_current_target(e);
lv_obj_t * calendar = lv_obj_get_parent(header);
const lv_calendar_date_t * cur_date = lv_calendar_get_showed_date(calendar);
lv_obj_t * year_dd = lv_obj_get_child(header, 0);
lv_obj_t * month_dd = lv_obj_get_child(header, 1);
const char * year_p = lv_dropdown_get_options(year_dd);
/* NOTE: Assumes YYYY format */
const int32_t first_year = (year_p[0] - '0') * 1000 +
(year_p[1] - '0') * 100 +
(year_p[2] - '0') * 10 + (year_p[3] - '0');
lv_dropdown_set_selected(year_dd, LV_ABS(first_year - cur_date->year));
lv_dropdown_set_selected(month_dd, cur_date->month - 1);
}
#endif /*LV_USE_CALENDAR_HEADER_ARROW*/
@@ -0,0 +1,62 @@
/**
* @file lv_calendar_header_dropdown.h
*
*/
#ifndef LV_CALENDAR_HEADER_DROPDOWN_H
#define LV_CALENDAR_HEADER_DROPDOWN_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj.h"
#if LV_USE_CALENDAR && LV_USE_CALENDAR_HEADER_DROPDOWN
#if LV_USE_DROPDOWN == 0
#error "LV_USE_DROPDOWN needs to be enabled"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_calendar_header_dropdown_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a calendar header with drop-drowns to select the year and month
* @param parent pointer to a calendar object.
* @return the created header
*/
lv_obj_t * lv_calendar_add_header_dropdown(lv_obj_t * parent);
/**
* Sets a custom calendar year list
* @param parent pointer to a calendar object
* @param years_list pointer to an const char array with the years list, see lv_dropdown set_options for more information.
* E.g. `const char * years = "2023\n2022\n2021\n2020\n2019"
* Only the pointer will be saved so this variable can't be local which will be destroyed later.
*/
void lv_calendar_header_dropdown_set_year_list(lv_obj_t * parent, const char * years_list);
/**********************
* MACROS
**********************/
#endif /*LV_USE_CALENDAR_HEADER_ARROW*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_CALENDAR_HEADER_DROPDOWN_H*/
@@ -0,0 +1,70 @@
/**
* @file lv_calendar_private.h
*
*/
#ifndef LV_CALENDAR_PRIVATE_H
#define LV_CALENDAR_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../core/lv_obj_private.h"
#include "lv_calendar.h"
#if LV_USE_CALENDAR
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/** Data of calendar */
struct _lv_calendar_t {
lv_obj_t obj;
/* New data for this type */
lv_obj_t * btnm;
lv_calendar_date_t today; /**< Date of today */
lv_calendar_date_t showed_date; /**< Currently visible month (day is ignored) */
lv_calendar_date_t * highlighted_dates; /**< Apply different style on these days (pointer to user-defined array) */
size_t highlighted_dates_num; /**< Number of elements in `highlighted_days` */
const char * map[8 * 7];
#ifdef LV_USE_CALENDAR_CHINESE
bool use_chinese_calendar;
/** 7 * 6: A week has 7 days, and the calendar displays 6 weeks in total.
* 20: Including the number of dates, line breaks, names for each day,
* and reserving several spaces for addresses. */
char nums [7 * 6][20];
#else
/** 7 * 6: A week has 7 days, and the calendar displays 6 weeks in total.
* 6: Including the number of dates, and reserving several spaces for
* addresses.*/
char nums [7 * 6][4];
#endif
};
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /* LV_USE_CALENDAR */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_CALENDAR_PRIVATE_H*/