Theme - distinct style for the same lv_obj_class

What do you want to achieve?

One of the most basic use case for themes, is to apply distinct style to different types of the same object. Like in css, you can have a “red button” and a “blue button”. Both are buttons, but we apply different styles to them.
From the VERY SCARCE documentation for the themes it looks like we should now implement an apply_cb function that will apply styles to widgets based on the “lv_obj_class”. Documentation for lv_obj_class is nonexisting, but it seems, that every builtin widget has it’s one own class. Therefore it’s impossible to distinguish “red button” from “blue button” just looking on the lv_obj_class, because they have the same class.

What have you tried so far?

I tried hiding an enum of the button type inside user data of the widget, but i’m not satisfied with the solution as I need the user data for other usage.
Of course I can manualy apply styles to my widget but that’s not the idea behind themes I guess.
It seems that there is some way to create a new, inherited lv_obj_class to have my own “red button” and “blue button” class, but it’s not documented and seems like an overkill.

Question

So what is the proper way to do it? It seems like a very basic thing to do, yet there is no documented solution. Please point me in the right direction.

Environment

  • MCU/MPU/Board: PC simulator, ESP32S3
  • LVGL version: 9.5

Hi @kdluzynski, To achieve what you want I think you have to create your own class for each type of button to diferenciate it in the apply theme callback using lv_obj_check_type() function. If you use LVGL pro you can use subjects to change bind styles and create themes.

This can help you create your own class:

Or instead of two widgets you can create just one button and add custom flags/properties to change its types between red/blue on the theme apply callback

Thank’s for the hint - It’s not very well documented and so it seems a bit like a hack, but it definitely works. Just for the record - this is a small snippet how I use it:
I define lightweight classes:

/* --- Buttons --- */
extern const lv_obj_class_t settings_list_button_class;

...

#define CLS_OBJ(name, base) const lv_obj_class_t name = { .base_class = &base, .instance_size = sizeof(lv_obj_t) }
#define CLS_BTN(name) const lv_obj_class_t name = { .base_class = &lv_button_class, .instance_size = sizeof(lv_button_t) }
#define CLS_LBL(name) const lv_obj_class_t name = { .base_class = &lv_label_class, .instance_size = sizeof(lv_label_t) }
#define CLS_LBL_INH(name,base) const lv_obj_class_t name = { .base_class = &base, .instance_size = sizeof(lv_label_t) }

/* Containers */
CLS_OBJ(page_button_matrix_class, lv_obj_class);
...
/* Labels */
CLS_LBL(label_default_class);
CLS_LBL(label_30_bold_class); CLS_LBL_INH(label_30_bold_white_class,label_30_bold_class); 
/* Buttons */
CLS_BTN(settings_list_button_class);

Then i have some helper functions that will call either lv_something_create or lv_obj_class_create_obj

lv_obj_t* obj_create_init(const lv_obj_class_t* obj_class,lv_obj_t* parent)
{
    lv_obj_t* obj = lv_obj_class_create_obj(obj_class,parent);
    lv_obj_class_init_obj(obj);
    return obj;
}

lv_obj_t* create_label(lv_obj_t * parent, std::string_view text, int32_t x, int32_t y, const lv_obj_class_t *label_class) {
    lv_obj_t * label = label_class ? obj_create_init(label_class, parent):lv_label_create(parent);
    lv_label_set_text(label, text.data());
    lv_obj_set_pos(label, x, y);
    lv_label_set_long_mode(label, LV_LABEL_LONG_CLIP);
    return label;
}