From 2e08f80361a9d7e5b97f49af6afc3549ffbf2758 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 25 Oct 2021 18:38:51 +0200 Subject: [PATCH] feat(calendar): add the header directly into the calendar widget In v8.0 the header was a detached object which made it difficult to move the header and the calendar together. Besides there were no way to notifi the header of the calendar's shown date has changed. BREAKING CHANGE: API of cleander headers, the appearence of the calendars related to #2573" --- docs/widgets/extra/calendar.md | 9 +-- .../widgets/calendar/lv_example_calendar_1.c | 7 +- src/extra/themes/default/lv_theme_default.c | 61 ++++++++++------ src/extra/widgets/calendar/lv_calendar.c | 71 ++++++++++--------- src/extra/widgets/calendar/lv_calendar.h | 19 ++++- .../calendar/lv_calendar_header_arrow.c | 54 +++++++------- .../calendar/lv_calendar_header_arrow.h | 8 +-- .../calendar/lv_calendar_header_dropdown.c | 49 ++++++------- .../calendar/lv_calendar_header_dropdown.h | 8 +-- src/widgets/lv_label.c | 10 ++- 10 files changed, 174 insertions(+), 122 deletions(-) diff --git a/docs/widgets/extra/calendar.md b/docs/widgets/extra/calendar.md index 05ce4cfef..e2ae454a9 100644 --- a/docs/widgets/extra/calendar.md +++ b/docs/widgets/extra/calendar.md @@ -14,7 +14,7 @@ The Calendar object is a classic calendar which can: The Calendar is added to the default group (if it is set). Calendar is an editable object which allow selecting and clicking the dates with encoder navigation too. -To make the Calendar flexible, by default it doesn't show the current year or month. Instead, there are external "headers" that can be attached to the calendar. +To make the Calendar flexible, by default it doesn't show the current year or month. Instead, there are optional "headers" that can be attached to the calendar. ## Parts and Styles The calendar object uses the [Button matrix](/widgets/core/btnmatrix) object under the hood to arrange the days into a matrix. @@ -57,16 +57,17 @@ Learn more about [Keys](/overview/indev). ## Headers +**From v8.1 the header is added directly into the Calendar widget and the API of the headers has been changed. ** + ### Arrow buttons -`lv_calendar_header_arrow_create(parent, calendar, button_size)` creates a header that contains a left and right arrow on the sides and a text with the current year and month between them. +`lv_calendar_header_arrow_create(calendar)` creates a header that contains a left and right arrow on the sides and a text with the current year and month between them. ### Drop-down -`lv_calendar_header_dropdown_create(parent, calendar)` creates a header that contains 2 drop-drown lists: one for the year and another for the month. +`lv_calendar_header_dropdown_create(calendar)` creates a header that contains 2 drop-drown lists: one for the year and another for the month. - ## Example ```eval_rst diff --git a/examples/widgets/calendar/lv_example_calendar_1.c b/examples/widgets/calendar/lv_example_calendar_1.c index bf2aa625f..e76df2ed7 100644 --- a/examples/widgets/calendar/lv_example_calendar_1.c +++ b/examples/widgets/calendar/lv_example_calendar_1.c @@ -4,7 +4,7 @@ static void event_handler(lv_event_t * e) { lv_event_code_t code = lv_event_get_code(e); - lv_obj_t * obj = lv_event_get_target(e); + lv_obj_t * obj = lv_event_get_current_target(e); if(code == LV_EVENT_VALUE_CHANGED) { lv_calendar_date_t date; @@ -41,10 +41,11 @@ void lv_example_calendar_1(void) lv_calendar_set_highlighted_dates(calendar, highlighted_days, 3); #if LV_USE_CALENDAR_HEADER_DROPDOWN - lv_calendar_header_dropdown_create(lv_scr_act(), calendar); + lv_calendar_header_dropdown_create(calendar); #elif LV_USE_CALENDAR_HEADER_ARROW - lv_calendar_header_arrow_create(lv_scr_act(), calendar, 25); + lv_calendar_header_arrow_create(calendar); #endif + lv_calendar_set_showed_date(calendar, 2021, 10); } #endif diff --git a/src/extra/themes/default/lv_theme_default.c b/src/extra/themes/default/lv_theme_default.c index 921c32dbe..479dba47f 100644 --- a/src/extra/themes/default/lv_theme_default.c +++ b/src/extra/themes/default/lv_theme_default.c @@ -118,7 +118,7 @@ typedef struct { #endif #if LV_USE_CALENDAR - lv_style_t calendar_bg, calendar_day; + lv_style_t calendar_btnm_bg, calendar_btnm_day, calendar_header; #endif #if LV_USE_COLORWHEEL @@ -489,16 +489,21 @@ static void style_init(void) #endif #if LV_USE_CALENDAR - style_init_reset(&styles->calendar_bg); - lv_style_set_pad_all(&styles->calendar_bg, PAD_SMALL); - lv_style_set_pad_gap(&styles->calendar_bg, PAD_SMALL / 2); - lv_style_set_radius(&styles->calendar_bg, 0); + style_init_reset(&styles->calendar_btnm_bg); + lv_style_set_pad_all(&styles->calendar_btnm_bg, PAD_SMALL); + lv_style_set_pad_gap(&styles->calendar_btnm_bg, PAD_SMALL / 2); - style_init_reset(&styles->calendar_day); - lv_style_set_border_width(&styles->calendar_day, lv_disp_dpx(theme.disp, 1)); - lv_style_set_border_color(&styles->calendar_day, color_grey); - lv_style_set_bg_color(&styles->calendar_day, color_card); - lv_style_set_bg_opa(&styles->calendar_day, LV_OPA_20); + style_init_reset(&styles->calendar_btnm_day); + lv_style_set_border_width(&styles->calendar_btnm_day, lv_disp_dpx(theme.disp, 1)); + lv_style_set_border_color(&styles->calendar_btnm_day, color_grey); + lv_style_set_bg_color(&styles->calendar_btnm_day, color_card); + lv_style_set_bg_opa(&styles->calendar_btnm_day, LV_OPA_20); + + style_init_reset(&styles->calendar_header); + lv_style_set_pad_hor(&styles->calendar_header, PAD_SMALL); + lv_style_set_pad_top(&styles->calendar_header, PAD_SMALL); + lv_style_set_pad_bottom(&styles->calendar_header, PAD_TINY); + lv_style_set_pad_gap(&styles->calendar_header, PAD_SMALL); #endif #if LV_USE_COLORWHEEL @@ -659,6 +664,15 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) return; } #endif + + +#if LV_USE_CALENDAR + else if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_calendar_class)) { + /*No style*/ + return; + } +#endif + lv_obj_add_style(obj, &styles->card, 0); lv_obj_add_style(obj, &styles->scrollbar, LV_PART_SCROLLBAR); lv_obj_add_style(obj, &styles->scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED); @@ -714,6 +728,20 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) return; } #endif + +#if LV_USE_CALENDAR + if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_calendar_class)) { + lv_obj_add_style(obj, &styles->calendar_btnm_bg, 0); + lv_obj_add_style(obj, &styles->outline_primary, LV_STATE_FOCUS_KEY); + lv_obj_add_style(obj, &styles->outline_secondary, LV_STATE_EDITED); + lv_obj_add_style(obj, &styles->calendar_btnm_day, LV_PART_ITEMS); + lv_obj_add_style(obj, &styles->pressed, LV_PART_ITEMS | LV_STATE_PRESSED); + lv_obj_add_style(obj, &styles->disabled, LV_PART_ITEMS | LV_STATE_DISABLED); + lv_obj_add_style(obj, &styles->outline_primary, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); + lv_obj_add_style(obj, &styles->outline_secondary, LV_PART_ITEMS | LV_STATE_EDITED); + return; + } +#endif lv_obj_add_style(obj, &styles->card, 0); lv_obj_add_style(obj, &styles->outline_primary, LV_STATE_FOCUS_KEY); lv_obj_add_style(obj, &styles->outline_secondary, LV_STATE_EDITED); @@ -901,26 +929,19 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) #if LV_USE_CALENDAR else if(lv_obj_check_type(obj, &lv_calendar_class)) { lv_obj_add_style(obj, &styles->card, 0); - lv_obj_add_style(obj, &styles->calendar_bg, 0); - lv_obj_add_style(obj, &styles->outline_primary, LV_STATE_FOCUS_KEY); - lv_obj_add_style(obj, &styles->outline_secondary, LV_STATE_EDITED); - lv_obj_add_style(obj, &styles->calendar_day, LV_PART_ITEMS); - lv_obj_add_style(obj, &styles->pressed, LV_PART_ITEMS | LV_STATE_PRESSED); - lv_obj_add_style(obj, &styles->disabled, LV_PART_ITEMS | LV_STATE_DISABLED); - lv_obj_add_style(obj, &styles->outline_primary, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - lv_obj_add_style(obj, &styles->outline_secondary, LV_PART_ITEMS | LV_STATE_EDITED); + lv_obj_add_style(obj, &styles->pad_zero, 0); } #endif #if LV_USE_CALENDAR_HEADER_ARROW else if(lv_obj_check_type(obj, &lv_calendar_header_arrow_class)) { - lv_obj_add_style(obj, &styles->card, 0); + lv_obj_add_style(obj, &styles->calendar_header, 0); } #endif #if LV_USE_CALENDAR_HEADER_DROPDOWN else if(lv_obj_check_type(obj, &lv_calendar_header_dropdown_class)) { - lv_obj_add_style(obj, &styles->card, 0); + lv_obj_add_style(obj, &styles->calendar_header, 0); } #endif diff --git a/src/extra/widgets/calendar/lv_calendar.c b/src/extra/widgets/calendar/lv_calendar.c index 8e25247ce..3ba73ea30 100644 --- a/src/extra/widgets/calendar/lv_calendar.c +++ b/src/extra/widgets/calendar/lv_calendar.c @@ -44,10 +44,9 @@ const lv_obj_class_t lv_calendar_class = { .height_def = (LV_DPI_DEF * 3) / 2, .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE, .instance_size = sizeof(lv_calendar_t), - .base_class = &lv_btnmatrix_class + .base_class = &lv_obj_class }; - static const char * day_names_def[7] = LV_CALENDAR_DEFAULT_DAY_NAMES; /********************** @@ -79,6 +78,7 @@ void lv_calendar_set_day_names(lv_obj_t * obj, const char * day_names[]) 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) @@ -123,9 +123,9 @@ void lv_calendar_set_showed_date(lv_obj_t * obj, uint32_t year, uint32_t month) uint8_t i; /*Remove the disabled state but revert it for day names*/ - lv_btnmatrix_clear_btn_ctrl_all(obj, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_clear_btn_ctrl_all(calendar->btnm, LV_BTNMATRIX_CTRL_DISABLED); for(i = 0; i < 7; i++) { - lv_btnmatrix_set_btn_ctrl(obj, i, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(calendar->btnm, i, LV_BTNMATRIX_CTRL_DISABLED); } uint8_t act_mo_len = get_month_length(d.year, d.month); @@ -138,33 +138,44 @@ void lv_calendar_set_showed_date(lv_obj_t * obj, uint32_t year, uint32_t month) uint8_t prev_mo_len = get_month_length(d.year, d.month - 1); for(i = 0, c = prev_mo_len - day_first + 1; i < day_first; i++, c++) { lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c); - lv_btnmatrix_set_btn_ctrl(obj, i + 7, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(calendar->btnm, i + 7, LV_BTNMATRIX_CTRL_DISABLED); } for(i = day_first + act_mo_len, c = 1; i < 6 * 7; i++, c++) { lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c); - lv_btnmatrix_set_btn_ctrl(obj, i + 7, LV_BTNMATRIX_CTRL_DISABLED); + lv_btnmatrix_set_btn_ctrl(calendar->btnm, i + 7, LV_BTNMATRIX_CTRL_DISABLED); } highlight_update(obj); /*Reset the focused button if the days changes*/ - if(lv_btnmatrix_get_selected_btn(obj) != LV_BTNMATRIX_BTN_NONE) { - lv_btnmatrix_set_selected_btn(obj, day_first + 7); + if(lv_btnmatrix_get_selected_btn(calendar->btnm) != LV_BTNMATRIX_BTN_NONE) { + lv_btnmatrix_set_selected_btn(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_cnt(obj); + for(i = 0; i < child_cnt; i++) { + lv_obj_t * child = lv_obj_get_child(obj, i); + if(child == calendar->btnm) continue; + lv_event_send(child, LV_EVENT_VALUE_CHANGED, obj); + } } /*===================== * Getter functions *====================*/ -/** - * 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. - */ +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); @@ -173,11 +184,6 @@ const lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * obj) return &calendar->today; } -/** - * 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 * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); @@ -186,11 +192,6 @@ const lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * obj) return &calendar->showed_date; } -/** - * Get the 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 * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); @@ -212,7 +213,7 @@ lv_res_t lv_calendar_get_pressed_date(const lv_obj_t * obj, lv_calendar_date_t * LV_ASSERT_OBJ(obj, MY_CLASS); lv_calendar_t * calendar = (lv_calendar_t *)obj; - uint16_t d = lv_btnmatrix_get_selected_btn(obj); + uint16_t d = lv_btnmatrix_get_selected_btn(calendar->btnm); if(d == LV_BTNMATRIX_BTN_NONE) { date->year = 0; date->month = 0; @@ -220,7 +221,7 @@ lv_res_t lv_calendar_get_pressed_date(const lv_obj_t * obj, lv_calendar_date_t * return LV_RES_INV; } - const char * txt = lv_btnmatrix_get_btn_text(obj, lv_btnmatrix_get_selected_btn(obj)); + const char * txt = lv_btnmatrix_get_btn_text(calendar->btnm, lv_btnmatrix_get_selected_btn(calendar->btnm)); if(txt[1] == 0) date->day = txt[0] - '0'; else date->day = (txt[0] - '0') * 10 + (txt[1] - '0'); @@ -272,14 +273,19 @@ static void lv_calendar_constructor(const lv_obj_class_t * class_p, lv_obj_t * o } calendar->map[8 * 7 - 1] = ""; - lv_btnmatrix_set_map(obj, calendar->map); - lv_btnmatrix_set_btn_ctrl_all(obj, LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_NO_REPEAT); + calendar->btnm = lv_btnmatrix_create(obj); + lv_btnmatrix_set_map(calendar->btnm, calendar->map); + lv_btnmatrix_set_btn_ctrl_all(calendar->btnm, LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_NO_REPEAT); + lv_obj_add_event_cb(calendar->btnm, draw_part_begin_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); + lv_obj_set_width(calendar->btnm, lv_pct(100)); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_grow(calendar->btnm, 1); lv_calendar_set_showed_date(obj, calendar->showed_date.year, calendar->showed_date.month); lv_calendar_set_today_date(obj, calendar->today.year, calendar->today.month, calendar->today.day); - lv_obj_add_event_cb(obj, draw_part_begin_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); + lv_obj_add_flag(calendar->btnm, LV_OBJ_FLAG_EVENT_BUBBLE); } static void draw_part_begin_event_cb(lv_event_t * e) @@ -315,9 +321,6 @@ static void draw_part_begin_event_cb(lv_event_t * e) } } - - - /** * Get the number of days in a month * @param year a year @@ -378,20 +381,20 @@ static void highlight_update(lv_obj_t * obj) uint16_t i; /*Clear all kind of selection*/ - lv_btnmatrix_clear_btn_ctrl_all(obj, LV_CALENDAR_CTRL_TODAY | LV_CALENDAR_CTRL_HIGHLIGHT); + lv_btnmatrix_clear_btn_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_btnmatrix_set_btn_ctrl(obj, calendar->highlighted_dates[i].day - 1 + day_first + 7, LV_CALENDAR_CTRL_HIGHLIGHT); + lv_btnmatrix_set_btn_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_btnmatrix_set_btn_ctrl(obj, calendar->today.day - 1 + day_first + 7, LV_CALENDAR_CTRL_TODAY); + lv_btnmatrix_set_btn_ctrl(calendar->btnm, calendar->today.day - 1 + day_first + 7, LV_CALENDAR_CTRL_TODAY); } } diff --git a/src/extra/widgets/calendar/lv_calendar.h b/src/extra/widgets/calendar/lv_calendar.h index 89cee9637..afda7ab92 100644 --- a/src/extra/widgets/calendar/lv_calendar.h +++ b/src/extra/widgets/calendar/lv_calendar.h @@ -36,7 +36,8 @@ typedef struct { /*Data of calendar*/ typedef struct { - lv_btnmatrix_t btnm; + lv_obj_t obj; + lv_obj_t * btnm; /*New data for this type*/ lv_calendar_date_t today; /*Date of today*/ lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ @@ -102,6 +103,22 @@ void lv_calendar_set_day_names(lv_obj_t * obj, const char ** day_names); * Getter functions *====================*/ +/** + * Get the header object of the calendar. + * Date selectors can be created here + * @param obj pointer to a calendar object + * @return pointer to a container (lv_obj) for a header + */ +lv_obj_t * lv_calendar_get_header(const lv_obj_t * obj); + +/** + * 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 diff --git a/src/extra/widgets/calendar/lv_calendar_header_arrow.c b/src/extra/widgets/calendar/lv_calendar_header_arrow.c index 890ce49d8..fecb1392e 100644 --- a/src/extra/widgets/calendar/lv_calendar_header_arrow.c +++ b/src/extra/widgets/calendar/lv_calendar_header_arrow.c @@ -27,18 +27,19 @@ **********************/ 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 + .constructor_cb = my_constructor, + .width_def = LV_PCT(100), + .height_def = LV_DPI_DEF / 3 }; static const char * month_names_def[12] = LV_CALENDAR_DEFAULT_MONTH_NAMES; -static lv_obj_t * calendar_param; -static lv_coord_t btn_size_param; /********************** * MACROS @@ -48,10 +49,8 @@ static lv_coord_t btn_size_param; * GLOBAL FUNCTIONS **********************/ -lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent, lv_obj_t * calendar, lv_coord_t btn_size) +lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent) { - calendar_param = calendar; - btn_size_param = btn_size; lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_arrow_class, parent); lv_obj_class_init_obj(obj); return obj; @@ -67,41 +66,36 @@ static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) LV_UNUSED(class_p); - /*Use the same paddings as the calendar_param*/ - lv_obj_set_style_pad_left(obj, lv_obj_get_style_pad_left(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_right(obj, lv_obj_get_style_pad_right(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_top(obj, lv_obj_get_style_pad_top(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_bottom(obj, lv_obj_get_style_pad_bottom(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_column(obj, lv_obj_get_style_pad_column(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_radius(obj, lv_obj_get_style_radius(calendar_param, LV_PART_MAIN), 0); + lv_obj_move_to_index(obj, 0); - const lv_calendar_date_t * cur_date = lv_calendar_get_showed_date(calendar_param); - - lv_obj_update_layout(calendar_param); - lv_coord_t w = lv_obj_get_width(calendar_param); - lv_obj_set_size(obj, w, LV_SIZE_CONTENT); 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_btn_create(obj); lv_obj_set_style_bg_img_src(mo_prev, LV_SYMBOL_LEFT, 0); - lv_obj_set_size(mo_prev, btn_size_param, btn_size_param); - lv_obj_add_event_cb(mo_prev, month_event_cb, LV_EVENT_CLICKED, calendar_param); + lv_obj_set_height(mo_prev, lv_pct(100)); + lv_obj_update_layout(mo_prev); + lv_coord_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_clear_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_SCROLL_CIRCULAR); lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); lv_obj_set_flex_grow(label, 1); - lv_label_set_text_fmt(label, "%d %s", cur_date->year, month_names_def[cur_date->month - 1]); lv_obj_t * mo_next = lv_btn_create(obj); lv_obj_set_style_bg_img_src(mo_next, LV_SYMBOL_RIGHT, 0); - lv_obj_set_size(mo_next, btn_size_param, btn_size_param); - lv_obj_add_event_cb(mo_next, month_event_cb, LV_EVENT_CLICKED, calendar_param); + 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_clear_flag(mo_next, LV_OBJ_FLAG_CLICK_FOCUSABLE); - lv_obj_align_to(obj, calendar_param, LV_ALIGN_OUT_TOP_MID, 0, 0); + lv_obj_add_event_cb(obj, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); + /*Refresh the drop downs*/ + lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); } static void month_event_cb(lv_event_t * e) @@ -109,7 +103,7 @@ static void month_event_cb(lv_event_t * e) lv_obj_t * btn = lv_event_get_target(e); lv_obj_t * header = lv_obj_get_parent(btn); - lv_obj_t * calendar = lv_event_get_user_data(e); + lv_obj_t * calendar = lv_obj_get_parent(header); const lv_calendar_date_t * d; d = lv_calendar_get_showed_date(calendar); @@ -141,5 +135,15 @@ static void month_event_cb(lv_event_t * e) 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_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 * label = lv_obj_get_child(header, 1); + lv_label_set_text_fmt(label, "%d %s", cur_date->year, month_names_def[cur_date->month - 1]); +} + #endif /*LV_USE_CALENDAR_HEADER_ARROW*/ diff --git a/src/extra/widgets/calendar/lv_calendar_header_arrow.h b/src/extra/widgets/calendar/lv_calendar_header_arrow.h index b4e3b52e3..f33ef7dc8 100644 --- a/src/extra/widgets/calendar/lv_calendar_header_arrow.h +++ b/src/extra/widgets/calendar/lv_calendar_header_arrow.h @@ -30,11 +30,11 @@ extern const lv_obj_class_t lv_calendar_header_arrow_class; **********************/ /** - * Create a calendar objects - * @param par pointer to an object, it will be the parent of the new calendar - * @return pointer to the created calendar + * 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_header_arrow_create(lv_obj_t * parent, lv_obj_t * calendar, lv_coord_t btn_size); +lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent); /********************** * MACROS diff --git a/src/extra/widgets/calendar/lv_calendar_header_dropdown.c b/src/extra/widgets/calendar/lv_calendar_header_dropdown.c index 41d30445c..5e8f90d4a 100644 --- a/src/extra/widgets/calendar/lv_calendar_header_dropdown.c +++ b/src/extra/widgets/calendar/lv_calendar_header_dropdown.c @@ -27,12 +27,15 @@ 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 }; @@ -47,8 +50,6 @@ static const char * year_list = { "1920\n1919\n1918\n1917\n1916\n1915\n1914\n1913\n1912\n1911\n1910\n1909\n1908\n1907\n1906\n1905\n1904\n1903\n1902\n1901" }; -static lv_obj_t * calendar_param; - /********************** * MACROS **********************/ @@ -57,9 +58,8 @@ static lv_obj_t * calendar_param; * GLOBAL FUNCTIONS **********************/ -lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent, lv_obj_t * calendar) +lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent) { - calendar_param = calendar; lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_header_dropdown_class, parent); lv_obj_class_init_obj(obj); @@ -76,36 +76,23 @@ static void my_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) LV_UNUSED(class_p); - /*Use the same paddings as the calendar_param*/ - lv_obj_set_style_pad_left(obj, lv_obj_get_style_pad_left(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_right(obj, lv_obj_get_style_pad_right(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_top(obj, lv_obj_get_style_pad_top(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_bottom(obj, lv_obj_get_style_pad_bottom(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_pad_column(obj, lv_obj_get_style_pad_column(calendar_param, LV_PART_MAIN), 0); - lv_obj_set_style_radius(obj, lv_obj_get_style_radius(calendar_param, LV_PART_MAIN), 0); - - const lv_calendar_date_t * cur_date = lv_calendar_get_showed_date(calendar_param); - - lv_obj_update_layout(calendar_param); - lv_coord_t w = lv_obj_get_width(calendar_param); - lv_obj_set_size(obj, w, LV_SIZE_CONTENT); + 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_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START); lv_obj_t * year_dd = lv_dropdown_create(obj); lv_dropdown_set_options(year_dd, year_list); - lv_dropdown_set_selected(year_dd, 2023 - cur_date->year); - lv_obj_add_event_cb(year_dd, year_event_cb, LV_EVENT_VALUE_CHANGED, calendar_param); + 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_dropdown_set_selected(month_dd, cur_date->month - 1); - lv_obj_add_event_cb(month_dd, month_event_cb, LV_EVENT_VALUE_CHANGED, calendar_param); + 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_align_to(obj, calendar_param, LV_ALIGN_OUT_TOP_MID, 0, 0); - + lv_obj_add_event_cb(obj, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); + /*Refresh the drop downs*/ + lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); } static void month_event_cb(lv_event_t * e) @@ -122,6 +109,7 @@ static void month_event_cb(lv_event_t * e) lv_calendar_set_showed_date(calendar, newd.year, newd.month); } + static void year_event_cb(lv_event_t * e) { lv_obj_t * dropdown = lv_event_get_target(e); @@ -137,5 +125,18 @@ static void year_event_cb(lv_event_t * e) lv_calendar_set_showed_date(calendar, newd.year, newd.month); } +static void value_changed_event_cb(lv_event_t * e) +{ + lv_obj_t * header = lv_event_get_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_dropdown_set_selected(year_dd, 2023 - cur_date->year); + + lv_obj_t * month_dd = lv_obj_get_child(header, 1); + lv_dropdown_set_selected(month_dd, cur_date->month - 1); +} + #endif /*LV_USE_CALENDAR_HEADER_ARROW*/ diff --git a/src/extra/widgets/calendar/lv_calendar_header_dropdown.h b/src/extra/widgets/calendar/lv_calendar_header_dropdown.h index 8d6333d9d..7ce924e94 100644 --- a/src/extra/widgets/calendar/lv_calendar_header_dropdown.h +++ b/src/extra/widgets/calendar/lv_calendar_header_dropdown.h @@ -30,11 +30,11 @@ extern const lv_obj_class_t lv_calendar_header_dropdown_class; **********************/ /** - * Create a calendar objects - * @param par pointer to an object, it will be the parent of the new calendar - * @return pointer to the created calendar + * 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_header_dropdown_create(lv_obj_t * parent, lv_obj_t * calendar); +lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent); /********************** * MACROS diff --git a/src/widgets/lv_label.c b/src/widgets/lv_label.c index f9573473d..434b8d5c8 100644 --- a/src/widgets/lv_label.c +++ b/src/widgets/lv_label.c @@ -858,7 +858,11 @@ static void draw_main(lv_event_t * e) txt_coords.y2 = obj->coords.y2; } - lv_draw_label(&txt_coords, clip_area, &label_draw_dsc, label->text, hint); + if(label->long_mode == LV_LABEL_LONG_SCROLL || label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) { + lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); + } else { + lv_draw_label(&txt_coords, clip_area, &label_draw_dsc, label->text, hint); + } if(label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) { lv_point_t size; @@ -871,7 +875,7 @@ static void draw_main(lv_event_t * e) lv_font_get_glyph_width(label_draw_dsc.font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; label_draw_dsc.ofs_y = label->offset.y; - lv_draw_label(&txt_coords, clip_area, &label_draw_dsc, label->text, hint); + lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); } /*Draw the text again below the original to make a circular effect */ @@ -879,7 +883,7 @@ static void draw_main(lv_event_t * e) label_draw_dsc.ofs_x = label->offset.x; label_draw_dsc.ofs_y = label->offset.y + size.y + lv_font_get_line_height(label_draw_dsc.font); - lv_draw_label(&txt_coords, clip_area, &label_draw_dsc, label->text, hint); + lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); } } }