How to scroll the parent Tileview

Description

Hello again,

I created a horizontal tileview consisting of objects, that fill each tile up. On one of these objects I created another tileview, but in the vertical direction. When I start the simulation, I can scroll through the horizontal tiles until I reach the tile with the vertical tileview. Then I can scroll in the horizontal direction, but I get trapped in the vertical tileview.

Is there a way I can address the horizontal scroll movement to the horizontal tileview when I’m inside the vertical tileview ?

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

VS2019-Simulator on Windows 10

What LVGL version are you using?

latest

What do you want to achieve?

Continue to scroll horizontally out of the vertical tileview.

What have you tried so far?

lv_obj_set_drag
lv_obj_set_drag_dir
lv_obj_set_drag_throw
lv_obj_set_drag_parent
lv_obj_set_parent_event

on both tileview (the vertical one) and it’s top tile.

Code to reproduce

//CREATE THE HORIZONTAL TILEVIEW
    static lv_point_t valid_pos[] = { {0,0},{1,0},{2,0} }; //Horizontal
    lv_obj_t * tileview = lv_tileview_create(lv_scr_act(), NULL);
    lv_tileview_set_valid_positions(tileview, valid_pos, 3); //Horizontal
    lv_obj_set_event_cb(tileview, my_event_cb);
    lv_tileview_set_edge_flash(tileview, false);

    lv_obj_t* tile1 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile1, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_tileview_add_element(tileview, tile1);

    lv_obj_t* tile2 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile2, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile2, LV_HOR_RES, 0);
    lv_obj_set_style_local_bg_color(tile2, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_obj_set_drag_parent(tile2, true);
    lv_tileview_add_element(tileview, tile2);

    lv_obj_t* tile3 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile3, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile3, 2 * LV_HOR_RES, 0);
    lv_obj_set_style_local_bg_color(tile3, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_tileview_add_element(tileview, tile3);

//CREATE THE VERTICAL TILEVIEW

    static lv_point_t valid_pos0[] = { {0,0},{0,1} }; //Vertikal
    lv_obj_t* tileview0 = lv_tileview_create(tile1, NULL);
    lv_obj_set_size(tileview0, LV_HOR_RES, LV_VER_RES);
    lv_tileview_set_valid_positions(tileview0, valid_pos0, 2); //Vertikal
    lv_tileview_set_edge_flash(tileview0, true);
            
    lv_obj_t* tile10 = lv_obj_create(tileview0, NULL); //Vertikal
    lv_obj_set_size(tile10, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile10, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_tileview_add_element(tileview0, tile10);

    lv_obj_t* tile20 = lv_obj_create(tileview0, NULL); //Vertikal
    lv_obj_set_size(tile20, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile20, 0, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile20, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
    lv_tileview_add_element(tileview0, tile20);

If you also want to have a vertical tileview why don’t you just set valid positions in the y-direction? I mean if you take a look at the docs then they actually feature an example were there is only one tileview but it scrolls in both directions. So that might be the best solution

I want to create another horizontal tileview in the bottom tile of the vertical tileview. That’s why I can’t use the existing hor/ver layout.

Okay, that’s fair. I have one “solution” then but I do not really like it, but maybe you can rework the idea so it suits you better.

void demo_init(void) {

//CREATE THE HORIZONTAL TILEVIEW
    static lv_point_t valid_pos[] = { {0,0},{1,0},{2,0},; //Horizontal
    tileview = lv_tileview_create(lv_scr_act(), NULL);
    lv_tileview_set_valid_positions(tileview, valid_pos, 3); //Horizontal
    //lv_obj_set_event_cb(tileview, my_event_cb);
    lv_tileview_set_edge_flash(tileview, false);

    lv_obj_t* tile1 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile1, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile1, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_tileview_add_element(tileview, tile1);

    lv_obj_t* tile2 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile2, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile2, LV_HOR_RES, 0);
    lv_obj_set_style_local_bg_color(tile2, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_obj_set_drag_parent(tile2, true);
    lv_tileview_add_element(tileview, tile2);

    lv_obj_t* tile3 = lv_obj_create(tileview, NULL); //Horizontal
    lv_obj_set_size(tile3, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile3, 2 * LV_HOR_RES, 0);
    lv_obj_set_style_local_bg_color(tile3, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER);
    lv_tileview_add_element(tileview, tile3);

    lv_obj_t* tile10 = lv_obj_create(tileview0, NULL); //Vertikal
    lv_obj_set_event_cb(tile10, event_cb);
    lv_obj_set_size(tile10, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile10, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_tileview_add_element(tileview0, tile10);

    lv_obj_t* tile20 = lv_obj_create(tileview0, NULL); //Vertikal
    lv_obj_set_size(tile20, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile20, 0, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile20, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
    lv_tileview_add_element(tileview0, tile20);*/

   //CREATE THE VERTICAL TILEVIEW

    static lv_point_t valid_pos0[] = { {0,0},{0,1} }; //Vertikal
    lv_obj_t* tileview0 = lv_tileview_create(tile1, NULL);
    lv_obj_set_size(tileview0, LV_HOR_RES, LV_VER_RES);
    lv_tileview_set_valid_positions(tileview0, valid_pos0, 2); //Vertikal
    lv_tileview_set_edge_flash(tileview0, true);
            
    lv_obj_t* tile10 = lv_obj_create(tileview0, NULL); //Vertikal
    lv_obj_set_event_cb(tile10, event_cb);
    lv_obj_set_size(tile10, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile10, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_tileview_add_element(tileview0, tile10);

    lv_obj_t* tile20 = lv_obj_create(tileview0, NULL); //Vertikal
    //lv_obj_set_event_cb(tile20, event_cb); //maybe leave this out? it might be more convenient but it up to you
    lv_obj_set_size(tile20, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_pos(tile20, 0, LV_VER_RES);
    lv_obj_set_style_local_bg_color(tile20, LV_OBJ_PART

The above code haven’t really changed too much, I believe. I have really only applied this event callback to the two vertical tiles. The premise of this callback is determining whether the use have moved more on the x-axis than the y-axis so to speak, If so then I manually switch to the next tile in the horizontal tileview with an animation of course. If I’m totally honest i don’t think that this is a good way of doing it but it works and it’s an idea that could be worked on. I’m doing this because your real problem is the two tileviews overlapping each other which essentially results in the callbacks/cliks and drags only reaching the one tileview in front

void event_cb(lv_obj_t* obj, lv_event_t event) {
    if (obj == NULL) return;
    if (event == LV_EVENT_PRESSED) {
        lv_indev_get_point(mouse, &FirstPoint);
    }
    if (event == LV_EVENT_RELEASED) {
        lv_indev_get_point(mouse, &LastPoint);
        if (abs(FirstPoint.x - LastPoint.x) > abs(FirstPoint.y - LastPoint.y)) {
            lv_tileview_set_tile_act(tileview, l, 0, LV_ANIM_ON);
        }
    }
}

I can´t see your reply, but the question was relevant. The variables FirstPoint and LastPoint are lv_point_t variables like so:

lv_point_t LastPoint;
lv_point_t FirstPoint;

And when it comes to the mouse variable, its a bit more “finicky” in lack of a better word. I believe(I’m a bit new to programming in general, and wasn’t the one who set up the basics of my “lvgl-project”) , that this should be the input device when running a simulator. Mine is declared like so:

const lv_indev_t * mouse = NULL;
/* Add the mouse (or touchpad) as input device
* Use the 'mouse' driver which reads the PC's mouse*/
mouse_init();
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);          /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = mouse_read;         /*This function will be called periodically (by the library) to get the mouse position and state*/
mouse = lv_indev_drv_register(&indev_drv);

But this means that this won’t work physically. In that case instead of the mouse input device, I would think that the right way to go about it, would be passing on the touchscreen “points”/presses. Hope this clears it a bit up for anyone wondering.

Just a note: you should be able to use lv_indev_get_act() to get the input device which sent an event like LV_EVENT_PRESSED/LV_EVENT_RELEASED.

Alright, I got @Rhaoma ‘s solution to work and I get the scrolling events!
Also [quote=“embeddedt, post:7, topic:4879”]
use lv_indev_get_act() to get the input device
[/quote]

was sufficient!

Thank you a lot!

@embeddedt can you think of another option to go for? When using the lv_tileview_set_act() the scrolling doesn’t look very natural. Is there any way to “transfer” the vertical scrolling / pointer move to the horizontal tileview?

As far as I know, the tileview is not designed for nesting, so I’m not sure there is a better way to achieve what you’re looking for. :slightly_frowning_face: