Caledar redraw/refresh optimizations

Description

I’m going through my project and trying to optimize the redrawing of things that don’t change visually. I’ve had the LV_USE_REFR_DEBUG set to on. Through the colourful boxes around things that are redrawn I’ve noticed when I select a new date on the calendar it’ll redraw the entire calendar and not just the previous and newly selected dates. Also when changing months (ie. lv_calendar_set_showed_date) the whole screen refreshes.

What MCU/Processor/Board and compiler are you using?

NXP MIMXRT1176CVM8A and Visual Studio Simulator
Compiler should be GNU99

What LVGL version are you using?

8.3.8

What do you want to achieve?

Only refresh the the objects that need to be refreshed to increase responsiveness and framerate.

What have you tried so far?

I tried modifying the code found here to fit into the calendar, since the calendar is mostly comprised of a btnmatrix.

Code to reproduce

The code block(s) should be formatted like:

typedef struct
{
    lv_obj_t* cal;
    lv_obj_t* cal_month_label;
    lv_obj_t* next;
    lv_obj_t* prev;
} lv_ui;

lv_ui ui;

// calendar
lv_style_t  calendar_base;
char month_names[12][20] = LV_CALENDAR_DEFAULT_MONTH_NAMES;

static void setup_calendar(lv_obj_t* parent, lv_obj_t** cal, uint32_t year, uint32_t month, uint32_t day, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h)
{
    *cal = lv_calendar_create(parent);
    lv_obj_set_pos(*cal, x, y);
    lv_obj_set_size(*cal, w, h);
    lv_calendar_set_today_date(*cal, year, month, day);
    lv_calendar_set_showed_date(*cal, year, month);
    lv_obj_add_style(*cal, &calendar_base, 0);
}


static void draw_custom_calendar(lv_event_t* e)
{
    lv_obj_t* obj = lv_event_get_target(e);
    lv_obj_draw_part_dsc_t* dsc = lv_event_get_param(e);

    if (dsc->part == LV_PART_ITEMS)
    {
        if (dsc->id < 7)
        {
            dsc->label_dsc->color = lv_color_hex(0x898989);
            dsc->label_dsc->font = &lv_font_montserrat_28;
        }
        else if(lv_btnmatrix_has_btn_ctrl(obj, dsc->id, LV_BTNMATRIX_CTRL_DISABLED))
        {
            dsc->rect_dsc->bg_opa = LV_OPA_0;
            dsc->label_dsc->color = lv_color_hex(0x898989);
            dsc->label_dsc->font = &lv_font_montserrat_24;
        }
        else
        {
            dsc->rect_dsc->bg_opa = 0;
            dsc->rect_dsc->border_width = 0;
            dsc->label_dsc->color = lv_color_hex(0x000000);
            dsc->label_dsc->font = &lv_font_montserrat_24;
        }

        if (lv_btnmatrix_has_btn_ctrl(obj, dsc->id, LV_BTNMATRIX_CTRL_CUSTOM_1))
        {
            dsc->rect_dsc->bg_color = lv_color_hex(0x2195f6);
            dsc->rect_dsc->bg_opa = LV_OPA_100;
            dsc->rect_dsc->border_width = 0;
            dsc->draw_area->x1 += (lv_area_get_width(dsc->draw_area) / 8) - 2;
            dsc->draw_area->x2 = dsc->draw_area->x1 + 80;
            dsc->draw_area->y1 -= 6;
            dsc->draw_area->y2 = dsc->draw_area->y1 + 80;
            dsc->rect_dsc->radius = 40;
            dsc->label_dsc->color = lv_color_hex(0xffffff);
            dsc->label_dsc->font = &lv_font_montserrat_24;
        }
    }
}

static void calendar_highlight_date (lv_event_t* e)
{
    lv_obj_t* obj = lv_event_get_current_target(e);

    lv_calendar_date_t date;
    if (lv_calendar_get_pressed_date(obj, &date))
    {
        lv_calendar_set_today_date(obj, date.year, date.month, date.day);
    }
}

static void month_scroll_forward_event (lv_event_t* e)
{
    const lv_calendar_date_t *date = lv_calendar_get_showed_date(ui.cal);
    lv_calendar_date_t new_date = *date;

    // Max date is December 2099
    if ((new_date.year == 2099) && (new_date.month == 12)) return;

    new_date.month = (new_date.month + 1 == 13 ? 1 : ++new_date.month); // increment month by 1, set to 1 if it would've been the 13th month
    if (new_date.month == 1) ++new_date.year; // if month switched to 1, increment the year by 1

    lv_label_set_text_fmt(ui.cal_month_label, "%s %d", month_names[new_date.month - 1], new_date.year);
    lv_calendar_set_showed_date(ui.cal, new_date.year, new_date.month);
}

static void month_scroll_backward_event (lv_event_t* e)
{
    const lv_calendar_date_t *date = lv_calendar_get_showed_date(ui.cal);
    lv_calendar_date_t new_date = *date;

    // Min date is January 2000
    if ((new_date.year == 2000) && (new_date.month == 1)) return;

    new_date.month = (new_date.month - 1 == 0 ? 12 : --new_date.month);
    if (new_date.month == 12) --new_date.year;

    lv_label_set_text_fmt(ui.cal_month_label, "%s %d", month_names[new_date.month - 1], new_date.year);
    lv_calendar_set_showed_date(ui.cal, new_date.year, new_date.month);
}

void setup_ui(lv_ui *ui)
{
	// Style for the base properties of a calendar
	lv_style_init(&calendar_base);
	lv_style_set_radius(&calendar_base, 10);
	lv_style_set_border_width(&calendar_base, 2);
	lv_style_set_border_color(&calendar_base, lv_color_hex(0x898989));
	lv_style_set_pad_top(&calendar_base, 50);

	setup_calendar(lv_scr_act(), &ui->cal, 2000, 1, 1, 20, 60, 770, 595);

    lv_calendar_t* cal = (lv_calendar_t*)ui->cal;
    lv_obj_add_event_cb(cal->btnm, draw_custom_calendar, LV_EVENT_DRAW_PART_BEGIN, NULL);
    lv_obj_add_event_cb(ui->cal, calendar_highlight_date, LV_EVENT_VALUE_CHANGED, NULL);

    ui->cal_month_label = lv_label_create(lv_scr_act());
    lv_obj_set_pos(ui->cal_month_label , 45, 80);
    lv_obj_set_size(ui->cal_month_label , 320, 40);
    lv_obj_set_style_text_align(ui->cal_month_label , LV_TEXT_ALIGN_LEFT, 0);
    lv_label_set_text_fmt(ui->cal_month_label, "%s %d", month_names[lv_calendar_get_today_date(ui->cal)->month - 1], lv_calendar_get_today_date(ui->cal)->year);
    lv_obj_set_style_text_font(ui->cal_month_label, &lv_font_montserrat_36, 0);

    ui->next = lv_img_create(lv_scr_act());
    lv_obj_set_size(ui->next, 70, 70);
    lv_obj_set_pos(ui->next, 700, 68);
    lv_img_set_src(ui->next, LV_SYMBOL_NEXT);
    lv_obj_add_flag(ui->next, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_set_style_pad_all(ui->next, 20, 0);

    ui->prev = lv_img_create(lv_scr_act());
    lv_obj_set_size(ui->prev, 70, 70);
    lv_obj_set_pos(ui->prev, 600, 68);
    lv_img_set_src(ui->prev, LV_SYMBOL_PREV);
    lv_obj_add_flag(ui->prev, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_set_style_pad_all(ui->prev, 20, 0);

    lv_obj_add_event_cb(ui->next, month_scroll_forward_event, LV_EVENT_RELEASED, NULL);
    lv_obj_add_event_cb(ui->prev, month_scroll_backward_event, LV_EVENT_RELEASED, NULL);
}

Code above will setup a calendar similar to what I have, I left out custom fonts and images, but when you press the previous and next month images in the top right you will see it will refresh the whole screen. By commenting things out I was able to figure out it is lv_calendar_set_showed_date that causes the refresh. Also when selecting a date you can see the whole calendar refresh on.

I took a video of the refreshing that I’m seeing. At first I click a different date and the whole calendar refreshes, after that I press the next and previous month buttons that make the whole screen refresh.