Menu with labels on ePaper

Description

I have made a menu using labels.
When I switch menu point I remove the background from the selected and draw for the next one.
I tried to use the minimal dependencies and the simplest components.

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

Configuration:

  • NUCLEO-L452RE
  • ICE Driving Board connected through SPI
  • ED043WC3 ePaper display
  • arm-gcc with -O1

What do you want to achieve?

The text of the label should have a padding like the background of the selected menu point would extend beyond the text.

What have you tried so far?

I have tried to add padding in the style of the label, but when I switch the selection the padding part of the background is not being cleared. I was wondering if it is possible to solve this issue somehow?

I have found the conversation in git about the best approach to create a menu and if it is not possible to solve with labels I will try that. (https://github.com/littlevgl/lvgl/issues/379)

Code to reproduce

void MainMenuScreen_ctor(void)
{
  /* Create GUI */
  LV_FONT_DECLARE(bpreplay_bold_35);
  LV_FONT_DECLARE(sw_symbols);

  /* Set screen properties */
  static lv_style_t style_screen;
  style_screen.body.main_color = LV_COLOR_WHITE;
  lv_style_copy(&style_screen, &lv_style_plain);
  lv_obj_set_style(lv_scr_act(), &style_screen);

  /*Create a new style*/
  lv_style_copy(&styleLight40_txt, &lv_style_plain);
  styleLight40_txt.text.font = &bpreplay_bold_35;
  styleLight40_txt.text.letter_space = 2;
  styleLight40_txt.text.line_space = 1;
  styleLight40_txt.text.color = LV_COLOR_BLACK;
  styleLight40_txt.body.padding.top = 8; // <<<<< This is the part which does not clear!!!
  styleLight40_txt.body.padding.bottom = 0;
  styleLight40_txt.body.padding.left = 8;// <<<<< This is the part which does not clear!!!
  styleLight40_txt.body.padding.right = 0;
  styleLight40_txt.body.main_color = LV_COLOR_SILVER;
  styleLight40_txt.body.grad_color = LV_COLOR_SILVER;
  styleLight40_txt.body.radius = 5;

  /*Create a new style*/
  lv_style_copy(&styleBold40Filled_txt, &lv_style_plain);
  styleBold40Filled_txt.text.font = &bpreplay_bold_35;
  styleBold40Filled_txt.text.letter_space = 2;
  styleBold40Filled_txt.text.line_space = 1;
  styleBold40Filled_txt.text.color = LV_COLOR_BLACK;
  styleBold40Filled_txt.body.padding.top = 40;
  styleBold40Filled_txt.body.padding.bottom = 40;
  styleBold40Filled_txt.body.main_color = LV_COLOR_SILVER;
  styleBold40Filled_txt.body.grad_color = LV_COLOR_SILVER;

  /*Create a new style*/
  lv_style_copy(&styleSymbols, &lv_style_plain);
  styleSymbols.text.font = &sw_symbols;
  styleSymbols.text.letter_space = 2;
  styleSymbols.text.line_space = 1;
  styleSymbols.text.color = LV_COLOR_BLACK;
  styleSymbols.body.padding.top = 24;
  styleSymbols.body.padding.bottom = 24;
  styleSymbols.body.main_color = LV_COLOR_GRAY;
  styleSymbols.body.grad_color = LV_COLOR_GRAY;

  /*Create a new label*/
  topLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(topLabel, &styleBold40Filled_txt);
  lv_label_set_long_mode(topLabel, LV_LABEL_LONG_CROP);
  lv_label_set_recolor(topLabel , true);
  lv_label_set_body_draw(topLabel, true);
  lv_obj_set_width(topLabel, 480);
  lv_obj_align(topLabel, NULL, LV_ALIGN_IN_TOP_MID, 0, 40);
  lv_label_set_align(topLabel, LV_LABEL_ALIGN_CENTER);

  /*Create a new label*/
  hotWaterLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(hotWaterLabel, &styleLight40_txt);
  lv_label_set_long_mode(hotWaterLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(hotWaterLabel, 400);
  lv_obj_set_height(hotWaterLabel, 64);
  lv_obj_align(hotWaterLabel, topLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 104);
  lv_label_set_align(hotWaterLabel, LV_LABEL_ALIGN_LEFT);

  /*Create a new label*/
  settingsLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(settingsLabel, &styleLight40_txt);
  lv_label_set_long_mode(settingsLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(settingsLabel, 400);
  lv_obj_set_height(settingsLabel, 56);
  lv_obj_align(settingsLabel, hotWaterLabel, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 16);
  lv_label_set_align(settingsLabel, LV_LABEL_ALIGN_LEFT);

  /*Create a new label*/
  helpLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(helpLabel, &styleLight40_txt);
  lv_label_set_long_mode(helpLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(helpLabel, 400);
  lv_obj_set_height(helpLabel, 56);
  lv_obj_align(helpLabel, settingsLabel, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 16);
  lv_label_set_align(helpLabel, LV_LABEL_ALIGN_LEFT);

  /*Create a new label*/
  arrowUpLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(arrowUpLabel, &styleSymbols);
  lv_label_set_long_mode(arrowUpLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(arrowUpLabel, 60);
  lv_obj_align(arrowUpLabel, helpLabel, LV_ALIGN_OUT_BOTTOM_LEFT, 160, 350);
  lv_label_set_align(arrowUpLabel, LV_LABEL_ALIGN_LEFT);

  /*Create a new label*/
  arrowDownLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(arrowDownLabel, &styleSymbols);
  lv_label_set_long_mode(arrowDownLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(arrowDownLabel, 60);
  lv_obj_align(arrowDownLabel, arrowUpLabel, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
  lv_label_set_align(arrowDownLabel, LV_LABEL_ALIGN_LEFT);
}

void selectMenuPoint(uint8_t highLightNr, uint8_t lastHighLightNr)
{
  switch (lastHighLightNr)
  {
    case 0:
      lv_label_set_body_draw(hotWaterStatus, false);
      break;
    case 1:
      lv_label_set_body_draw(settingsLabel, false);
      break;
    case 2:
      lv_label_set_body_draw(helpLabel, false);
      break;
    default:
      break;
  }

  switch (highLightNr)
  {
    case 0:
      lv_label_set_body_draw(hotWaterStatus, true);
      break;
    case 1:
      lv_label_set_body_draw(settingsLabel, true);
      break;
    case 2:
      lv_label_set_body_draw(helpLabel, true);
      break;
    default:
      break;
  }
}

Screenshot

What happens if you call lv_obj_invalidate on the label after calling lv_label_set_body_draw?

I’ve tried it with this code:


    lv_style_copy(&styleLight40_txt, &lv_style_plain);
    styleLight40_txt.text.letter_space = 2;
    styleLight40_txt.text.line_space = 1;
    styleLight40_txt.text.color = LV_COLOR_BLACK;
    styleLight40_txt.body.padding.top = 8; // <<<<< This is the part which does not clear!!!
    styleLight40_txt.body.padding.bottom = 16;
    styleLight40_txt.body.padding.left = 8;// <<<<< This is the part which does not clear!!!
    styleLight40_txt.body.padding.right = 16;
    styleLight40_txt.body.main_color = LV_COLOR_SILVER;
    styleLight40_txt.body.grad_color = LV_COLOR_SILVER;
    styleLight40_txt.body.radius = 5;


    topLabel = lv_label_create(lv_scr_act(), NULL);
    lv_obj_set_style(topLabel, &styleLight40_txt);
    lv_label_set_recolor(topLabel , true);
    lv_label_set_body_draw(topLabel, true);
    lv_obj_align(topLabel, NULL, LV_ALIGN_IN_TOP_MID, 0, 40);

And got this which look good to me:
image

I’m sure if it’s relevant here, but note that, the background doesn’t make the label really larger, it’s drawn only “virtually”. That is if you align the label, the text’s coordinates will matter.

I think the issue was with switching body_draw on and off, unless I misunderstood the original post.

Sorry for the late answer, I haven’t got an email about this. I will check my settings.
Exactly as @embeddedt mentioned. The problem is not to show the label, but to switch the highlight between two menu points.
I have tried your suggestion @embeddedt. Unfortunately the result is the same.
I think this is because what @kisvegabor mentioned. LvGL redraws the object, but as the highlight is not part of the object’s area, because it is bigger by the padding it does not include that part.
If you guys have any other idea please let me know, anyway I will give a try with buttons.

This one looks much better, but I am quite got stuck on how to position the label of the button vertically middle and add some padding on the left side. Just like the picture in my previous comment.

What you can see is the same action that I did above. Switching from Menu point 1 to Menu point 2.

Code:

  /*Create a new style*/
  lv_style_copy(&styleRelease, &lv_style_plain);
  styleRelease.text.font = &bpreplay_bold_35;
  styleRelease.text.letter_space = 2;
  styleRelease.text.line_space = 1;
  styleRelease.text.color = LV_COLOR_BLACK;
  styleRelease.body.main_color = LV_COLOR_WHITE;
  styleRelease.body.grad_color = LV_COLOR_WHITE;
  styleRelease.body.padding.top = 0;
  styleRelease.body.padding.bottom = 0;
  styleRelease.body.padding.left = 0;
  styleRelease.body.padding.right = 0;
  styleRelease.body.padding.inner = 0;

  lv_style_copy(&stylePressed, &lv_style_plain);
  stylePressed.text.font = &bpreplay_bold_35;
  stylePressed.text.letter_space = 2;
  stylePressed.text.line_space = 1;
  stylePressed.text.color = LV_COLOR_BLACK;
  stylePressed.body.main_color = LV_COLOR_GRAY;
  stylePressed.body.grad_color = LV_COLOR_GRAY;
  stylePressed.body.padding.top = 0;
  stylePressed.body.padding.bottom = 0;
  stylePressed.body.padding.left = 0;
  stylePressed.body.padding.right = 0;
  stylePressed.body.padding.inner = 0;

  buttonHotWater = lv_btn_create(lv_scr_act(), NULL);
	lv_obj_set_width(buttonHotWater, 400);
	lv_obj_set_height(buttonHotWater, 56);
  lv_btn_set_style(buttonHotWater, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonHotWater, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonHotWater, topLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 104);
	lv_btn_set_toggle(buttonHotWater, true);
	lv_btn_set_layout(buttonHotWater, LV_LAYOUT_OFF);

  buttonSettings = lv_btn_create(lv_scr_act(), NULL);
  lv_obj_set_width(buttonSettings, 400);
  lv_obj_set_height(buttonSettings, 56);
  lv_btn_set_style(buttonSettings, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonSettings, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonSettings, buttonHotWater, LV_ALIGN_OUT_BOTTOM_MID, 0, 16);
  lv_btn_set_toggle(buttonSettings, true);
  lv_btn_set_layout(buttonSettings, LV_LAYOUT_OFF);

  buttonHelp = lv_btn_create(lv_scr_act(), NULL);
  lv_obj_set_width(buttonHelp, 400);
  lv_obj_set_height(buttonHelp, 56);
  lv_btn_set_style(buttonHelp, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonHelp, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonHelp, buttonSettings, LV_ALIGN_OUT_BOTTOM_MID, 0, 16);
  lv_btn_set_toggle(buttonHelp, true);
  lv_btn_set_layout(buttonHelp, LV_LAYOUT_OFF);

And this is how I switch the highlight of a menu point.

lv_btn_set_state(buttonHotWater, (drawBackground? LV_BTN_STATE_TGL_PR: LV_BTN_STATE_TGL_REL));

Can you help me with positioning the label of the button?

Try using LV_LAYOUT_COL_L instead. When you turn off the layout the label will get aligned to the top left by default.

Nice, this is perfect now.
Thank you for your help guys. I think the solution is in multiple comments so I summarize here and set this as a solution.

  • Label is not the best choice for this type of menu, because the background which makes the highlight will not update entirely.
  • Toggle Button is the right way to do it with two different styles added to the button states.
  • To align the text of the button you have to set the layout of the button to LV_LAYOUT_COL_L and change the padding in the style.


Code:

  /* Create GUI */
  LV_FONT_DECLARE(bpreplay_bold_35);
  LV_FONT_DECLARE(sw_symbols);

  /* Set screen properties */
  static lv_style_t style_screen;
  style_screen.body.main_color = LV_COLOR_WHITE;
  lv_style_copy(&style_screen, &lv_style_plain);
  lv_obj_set_style(lv_scr_act(), &style_screen);

  /*Create a new style*/
  lv_style_copy(&styleBold40Filled_txt, &lv_style_plain);
  styleBold40Filled_txt.text.font = &bpreplay_bold_35;
  styleBold40Filled_txt.text.letter_space = 2;
  styleBold40Filled_txt.text.line_space = 1;
  styleBold40Filled_txt.text.color = LV_COLOR_BLACK;
  styleBold40Filled_txt.body.padding.top = 40;
  styleBold40Filled_txt.body.padding.bottom = 40;
  styleBold40Filled_txt.body.main_color = LV_COLOR_SILVER;
  styleBold40Filled_txt.body.grad_color = LV_COLOR_SILVER;

  /*Create a new style*/
  lv_style_copy(&styleSymbols, &lv_style_plain);
  styleSymbols.text.font = &sw_symbols;
  styleSymbols.text.letter_space = 2;
  styleSymbols.text.line_space = 1;
  styleSymbols.text.color = LV_COLOR_BLACK;
  styleSymbols.body.padding.top = 24;
  styleSymbols.body.padding.bottom = 24;
  styleSymbols.body.main_color = LV_COLOR_GRAY;
  styleSymbols.body.grad_color = LV_COLOR_GRAY;

  /*Create a new label*/
  topLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(topLabel, &styleBold40Filled_txt);
  lv_label_set_long_mode(topLabel, LV_LABEL_LONG_CROP);
  lv_label_set_recolor(topLabel , true);
  lv_label_set_body_draw(topLabel, true);
  lv_obj_set_width(topLabel, 480);
  lv_obj_align(topLabel, NULL, LV_ALIGN_IN_TOP_MID, 0, 40);
  lv_label_set_align(topLabel, LV_LABEL_ALIGN_CENTER);

  /*Create a new style*/
  lv_style_copy(&styleRelease, &lv_style_plain);
  styleRelease.text.font = &bpreplay_bold_35;
  styleRelease.text.letter_space = 2;
  styleRelease.text.line_space = 1;
  styleRelease.text.color = LV_COLOR_BLACK;
  styleRelease.body.main_color = LV_COLOR_WHITE;
  styleRelease.body.grad_color = LV_COLOR_WHITE;
  styleRelease.body.padding.top = 14;
  styleRelease.body.padding.bottom = 0;
  styleRelease.body.padding.left = 14;
  styleRelease.body.padding.right = 0;
  styleRelease.body.padding.inner = 0;
  styleRelease.body.radius = 5;

  /*Create a new style*/
  lv_style_copy(&stylePressed, &lv_style_plain);
  stylePressed.text.font = &bpreplay_bold_35;
  stylePressed.text.letter_space = 2;
  stylePressed.text.line_space = 1;
  stylePressed.text.color = LV_COLOR_BLACK;
  stylePressed.body.main_color = LV_COLOR_GRAY;
  stylePressed.body.grad_color = LV_COLOR_GRAY;
  stylePressed.body.padding.top = 14;
  stylePressed.body.padding.bottom = 0;
  stylePressed.body.padding.left = 14;
  stylePressed.body.padding.right = 0;
  stylePressed.body.padding.inner = 0;
  stylePressed.body.radius = 5;

  /*Create a new button and label*/
  buttonHotWater = lv_btn_create(lv_scr_act(), NULL);
	lv_obj_set_width(buttonHotWater, 400);
	lv_obj_set_height(buttonHotWater, 56);
  lv_btn_set_style(buttonHotWater, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonHotWater, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonHotWater, topLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 104);
	lv_btn_set_toggle(buttonHotWater, true);
	lv_btn_set_layout(buttonHotWater, LV_LAYOUT_COL_L);
	labelHotWater = lv_label_create(buttonHotWater, NULL);

	/*Create a new button and label*/
  buttonSettings = lv_btn_create(lv_scr_act(), NULL);
  lv_obj_set_width(buttonSettings, 400);
  lv_obj_set_height(buttonSettings, 56);
  lv_btn_set_style(buttonSettings, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonSettings, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonSettings, buttonHotWater, LV_ALIGN_OUT_BOTTOM_MID, 0, 16);
  lv_btn_set_toggle(buttonSettings, true);
  lv_btn_set_layout(buttonSettings, LV_LAYOUT_COL_L);
  labelSettings = lv_label_create(buttonSettings, NULL);

  /*Create a new button and label*/
  buttonHelp = lv_btn_create(lv_scr_act(), NULL);
  lv_obj_set_width(buttonHelp, 400);
  lv_obj_set_height(buttonHelp, 56);
  lv_btn_set_style(buttonHelp, LV_BTN_STYLE_TGL_PR, &stylePressed);
  lv_btn_set_style(buttonHelp, LV_BTN_STYLE_TGL_REL, &styleRelease);
  lv_obj_align(buttonHelp, buttonSettings, LV_ALIGN_OUT_BOTTOM_MID, 0, 16);
  lv_btn_set_toggle(buttonHelp, true);
  lv_btn_set_layout(buttonHelp, LV_LAYOUT_COL_L);
  labelHelp = lv_label_create(buttonHelp, NULL);

  /*Create a new label*/
  arrowUpLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(arrowUpLabel, &styleSymbols);
  lv_label_set_long_mode(arrowUpLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(arrowUpLabel, 60);
  lv_obj_align(arrowUpLabel, buttonHelp, LV_ALIGN_OUT_BOTTOM_LEFT, 160, 350);
  lv_label_set_align(arrowUpLabel, LV_LABEL_ALIGN_LEFT);

  /*Create a new label*/
  arrowDownLabel = lv_label_create(lv_scr_act(), NULL);
  lv_obj_set_style(arrowDownLabel, &styleSymbols);
  lv_label_set_long_mode(arrowDownLabel, LV_LABEL_LONG_CROP);
  lv_obj_set_width(arrowDownLabel, 60);
  lv_obj_align(arrowDownLabel, arrowUpLabel, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
  lv_label_set_align(arrowDownLabel, LV_LABEL_ALIGN_LEFT);

To change highlight:

lv_btn_set_state(buttonHotWater, (drawBackground? LV_BTN_STATE_TGL_PR: LV_BTN_STATE_TGL_REL));

I’m suspicious that that is a bug.

Yes, this is not the behaviour that I would expect from UI element, but if the background is not part of the label then this behaviour is explained to me.
Why is it like this?
A bit also unclear why are the padding and the background related to each other. Padding is a kind of distance keeping, it is not really expanding the background in general.

It already works “normally” in v7.0. The label really gets bigger due to padding.

1 Like