How to add image to all dropdown list items

Important: unclear posts may not receive useful answers.

Before posting

  • Get familiar with Markdown to format and structure your post
  • Be sure to update lvgl from the latest version from the master branch.
  • Be sure you have checked the FAQ and read the relevant part of the documentation.
  • If applicable use the Simulator to eliminate hardware related issues.

Delete this section if you read and applied the mentioned points.

Description

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

What LVGL version are you using?

8.3.2

What do you want to achieve?

Add icons in every dropdown list items
image

What have you tried so far?

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.

The code block(s) should be formatted like:

/*You code here*/

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

Hi all, I would like to know how to add an image in every dropdown list items. Reading the doc of the widget from here:
https://docs.lvgl.io/8.3/widgets/core/dropdown.html
seems not possible when adding the options (lv_dropdown_add_option)

Could be possible during the LV_EVENT_DRAW_PART_BEGIN event?

I’ve tried the following code but with no luck…

lv_obj_t * dropdown_list = lv_dropdown_get_list(dropdown);
lv_obj_add_event_cb(dropdown_list, dropdown_list_callback, LV_EVENT_ALL, NULL);

then in the dropdown_list_callback:
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_target(e);
if (code == LV_EVENT_DRAW_PART_BEGIN) {
lv_obj_t * list1 = lv_obj_get_parent(obj);
lv_obj_t *icon = lv_img_create(list1);
lv_img_set_src(icon, my_icon);
lv_obj_align(icon, LV_ALIGN_LEFT_MID, 10, 0);

	LV_LOG_USER("Clicked: %s", lv_list_get_btn_text(list1, obj));
	uint32_t i;
    for(i = 0; i < lv_obj_get_child_cnt(obj); i++) {
		lv_obj_t * child = lv_obj_get_child(obj, i);
		lv_obj_t *icon = lv_img_create(child);
		lv_img_set_src(icon, LV_SYMBOL_WIFI);
		lv_obj_align(icon, LV_ALIGN_LEFT_MID, 10, 0);
	}
}

Many thanks!

Hi @tzan ,

If I understand your question correctly you just want to use the font awesome icons built in to LVGL in which case it is straight forward :slight_smile: , see here:

void lv_example_dropdown_2(void)
{
    static const char * opts = LV_SYMBOL_WIFI" WI-FI\n"
    						   LV_SYMBOL_FILE" File\n"
							   LV_SYMBOL_BATTERY_FULL" Battery\n"
							   LV_SYMBOL_USB" USB";

    lv_obj_t * dd;
    dd = lv_dropdown_create(lv_scr_act());
    lv_dropdown_set_options_static(dd, opts);
    lv_obj_align(dd, LV_ALIGN_TOP_MID, 0, 10);

}

I hope that helps…

Kind Regards,

Pete

Hi @pete-pjb, thanks for your help.
I would like to add my custom image, like a png and not only the icons provided in the library like LV_SYMBOL_WIFI.

Many thanks!

@tzan Hmmm,

That is more of an issue, I will take a quick look and see if there is an easy way.

Kind Regards,

Pete

Hi @tzan ,

Having looked at the source code for the ‘dropdown’ it doesn’t really lend itself well to doing what you want, but here is something for you to experiment with:

char *icon_list[] = {

		LV_SYMBOL_WIFI,
		LV_SYMBOL_FILE,
		LV_SYMBOL_BATTERY_FULL,
		LV_SYMBOL_USB
};

void dd_cb( lv_event_t *e ) {

	static uint8_t		has_run = 0;
	uint16_t 			cnt;
	lv_event_code_t 	code = lv_event_get_code(e);
	lv_obj_t 			*obj = lv_event_get_target(e);

	if (code == LV_EVENT_READY && !has_run) {
	    lv_dropdown_t * dropdown = (lv_dropdown_t *)obj;
	    lv_obj_t * label = lv_obj_get_child(dropdown->list, 0);
	    const lv_font_t * font = lv_obj_get_style_text_font(label, LV_PART_MAIN);
	    lv_coord_t font_h = lv_font_get_line_height(font);
	    lv_coord_t line_space = lv_obj_get_style_text_line_space(label, LV_PART_MAIN);
	    lv_coord_t unit_h = font_h + line_space;
	    for( cnt = 0; cnt < dropdown->option_cnt; cnt++ ){
		    lv_obj_t *icon = lv_img_create((lv_obj_t*)dropdown->list);
		    lv_img_set_src(icon, icon_list[cnt]);
		    lv_obj_align( icon, LV_ALIGN_TOP_LEFT, 0, cnt * unit_h );
	    }
	    has_run = 1;
	}
}

void dd_example( lv_obj_t *parent ) {
	
    const char * opts = "        Wi-Fi\n"
                        "        File\n"
                        "        Battery\n"
                        "        USB";

    lv_obj_t *dd = lv_dropdown_create( parent );
    lv_dropdown_set_options_static(dd, opts);
    lv_obj_align(dd, LV_ALIGN_TOP_MID, 0, 10);
    lv_obj_add_event_cb(dd, dd_cb, LV_EVENT_READY, NULL);

}

dd_example( lv_scr_act() ); 

The icon list could now be any source type, although you will need to keep them to the size of the text etc. There are issues; the highlight bar hides the icon when the list is dropped and the icon does not show when the dropdown is closed. There may be ways to deal with the issues but I am unable to spend more time on it for now. Hopefully this will give you a starting point to carry on. You may also consider creating a custom widget based on the ‘lv_list’ which might be an easier approach in the long run. I think ultimately maybe the dropdown source should be rewritten to use the ‘lv_list’ as the list part which would make it much more flexible. If you fancy having a go at that I am sure it would be welcomed.

cc @kisvegabor

I hope that helps,

Kind Regards,

Pete

The drop down list widget is very simple to make it memory effective even for large lists.

To get functionality you wish you can use custom draw callback or you can use the lv_list widget that you can manually hide/show below a button.

1 Like

Hi @kisvegabor ,

Thanks for taking the time to comment and confirming the reasoning for the methodology of the dropdown implementation, which rules out the modification or rewriting of the widget.

So in summary @tzan is left with the choice of customising the draw event handler of which I have posted a skeleton example above or creating a new widget based on a lv_list or by his own means for his application.

Kind Regards,

Pete

1 Like