Lv_roller strange behavior when clearing/adding CLICKABLE flag

EDIT: The discussion here has gotten a bit off-topic and essentially started being about this issue: Disable input from "background" with messagebox - #2 by Tinus.

In short, the issue is that I was also setting the CLICKABLE flag on the roller’s children, which should not happen.

Hello, I have been trying to get this to work for a time now: Disable input from "background" with messagebox - #2 by Tinus

It all seemed to work fine, however I notice that the lv_roller elements in my application are really unresponsive after the LV_OBJ_FLAG_CLICKABLE has been cleared and then added again.
The rollers become “stiff” and do not respond to touches like they should.

Is there something I’m missing here with how the flags function? Please let me know.

I am using LVGL v8.3.0

Hi @Tinus ,

I have tried this issue in my side and it works well (in V8.3.2), update version may help you solve this problem. Or you could check the commits between 2 version, I think there’re not many commits since only 2 minor version update.

1 Like

Hi, thanks for responding!

Turns out this is my own fault, I had created a function to loop through all objects on screen and clear/set all clickable flags, so I could disable background input for a message box. However, it seems that all lv_roller objects also have (at least) 1 child.
Sorry for not properly testing before asking this question.

Setting this CLICKABLE flag on the rollers themselves is fine, but also setting it for the child of every roller seems to break them: it seems this child is in reality responsible for displaying the roller, as hiding it with the HIDDEN flag breaks the roller object in its entirety.

I think this child is of the type lv_roller_label, which is not supposed to have the CLICKABLE flag enabled, I suppose being able to click the label causes the roller to not work properly but I am not certain. Perhaps @kisvegabor can confirm?

For now I have fixed this by checking the object type with lv_obj_check_type(), if that object happens to be of type lv_rolller, I just do not change any flags. This works fine.

It’s really not recommended as there might be objects (e.g. the label of the roller) where LVGL carefully sets some flags. Overwriting these can really break the widgets.

I see, thanks for responding.

Sadly I do not see any other way to get the implementation that I want: Disable input from "background" with messagebox

The problem is that I have a rather large display and redrawing the entire thing just to disable the background for a small message box seems counter-intuitive.

The safest option would be to only clear/add flags on objects where this is is “safe” to do.
Is there perhaps a way to figure out which objects?

How about this for a solution. This is what I call “thinking outside the box”

When you are going to make a message box create an object that is the entire size of the display. set it as the top most object. clear the clickable flag and set all colors to have an opacity of 0. then create the message box on top of that object.

The “transparent” display sized object will consume all clicks except for the clicks that need to be seen by the message box. When the message box gets closed you can delete the object. Another option depending on how often message boxes appear is create the transparent object on program startup and set the hidden flag. when you want to put a message box up clear the hidden flag and set it as the topmost object and then create you message box and set it as the top most object. when box is closed reset the hidden flag. This will keep from creating and deleting objects a bunch of times if you use message boxes a lot in your code.

Just because it cannot be seen with the eyes doesn’t mean it doesn’t exist. I believe this will solve your issue and it does it in a graceful way. Iterating over all of the objects clearing a flag is not ideal as stated above.

I believe because it is completely transparent LVGL is not going to redraw the entire display because of it being added. @kisvegabor would be able to answer that question.

1 Like

I just wanted to suggest the same and usually I do it as well. With one difference: use lv_layer_top() as parent. You can learn more about layers here.

Actually there will be one redraw but LVGL will skip the transparent object very early during rendering.

If this extra redraw is an issue I can show how to get rid of it but it’s a little bit hacky.

1 Like

Thanks to both of you for your answers.

Sadly it does redraw the whole screen.

I am currently doing the following:

/* on screen init: */
background = lv_obj_create(lv_layer_top());
lv_obj_set_size(background, lv_pct(100), lv_pct(100));
lv_obj_set_style_bg_opa(background, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_flag(background, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(background, LV_OBJ_FLAG_CLICKABLE);

/* showing the dialog: */
lv_obj_clear_flag(background, LV_OBJ_FLAG_HIDDEN);

void show_confirm_dialog(lv_obj_t* background)
        msgBox = lv_msgbox_create(background, NULL, NULL, NULL, false);

*/ hiding the dialog: */
lv_obj_add_flag(background, LV_OBJ_FLAG_HIDDEN);

This does indeed also stop inputs from being registered: however, it will still attempt to draw the whole screen (even though the only visible change is the messagebox showing up) when using this method. This means the messagebox (or dialog) takes more than a second to show up. This is quite a bit slower than just disabling all input.

Do I need to change other opacity settings outside of the background?
Maybe that is the issue, if it is, I’ll change that. Otherwise, could you show me the hacky solution?

Kind regards

@kisvegabor said there is a way to stop it from rendering the screen when the transparent object is added. You may have to add the transparent object and stop the rendering from taking place and then add the message box and allow the render to take place.

Your other option which might be an even easier way to go about it is when a message box gets displayed to store the area of the message box in a global and set a flag and in the caallback that handles the touch portion of the display only report touch to LVGL if the touch is inside of that area. That would add the least invasive code to LVGL. It would be instant and you would not need to to do anything special in LVGL to handle this…

There is a callback that exists that gets set to the indev driver. If that caallback is being provided by a library then you can store the callback into a global and create a new callback and set that to the indev. Call the stored callback in the one you created to get the touch data and modify that touch data as needed to handle a message box being displayed.

1 Like

Note that the background object is not required. You can crate the message box directly on lv_layer_top() and make only the message box hidden/visible, and layer top clickable/not clickable.

So you can create the message box only once at the beginning and make it non-hidden. This way only it’s area will be redrawn. LV_USE_REFR_DEBUG in lv_conf.h can help to visualize the redrawn areas.

It just came to my mind that there is not too hacky method to solce the redraw issue.

lv_disp_enable_invalidation(NULL, false);
...create objects, change properties...
lv_disp_enable_invalidation(NULL, true);
lv_obj_invalidate(some_obj); // invalidate what is really needed.
1 Like

Hello, thanks once again to both of you for your answers :grin:.
I am sorry for steering this discussion off-topic.

This here:

fixed my issue! The whole screen does not get redrawn in this case and everything except the message box is un-clickable.

For those curious, it was really quite simple. Here’s the code:

lv_obj_add_flag(lv_layer_top(), LV_OBJ_FLAG_CLICKABLE); /* disable background input */
msgBox = lv_msgbox_create(lv_layer_top(), NULL, NULL, NULL, false); /* create message box */

/* Do something with message box.... */

lv_obj_clear_flag(lv_layer_top(), LV_OBJ_FLAG_CLICKABLE); /* enable background input */lv_msgbox_close(msgBox);
1 Like

Happy to hear that it works well now :slight_smile:

1 Like

Awesome, glad a solution was found.

1 Like