lvgl / lvgl

Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
https://lvgl.io
MIT License
16.13k stars 3.16k forks source link

What is the best way to create menu? #379

Closed sokolbiba closed 5 years ago

sokolbiba commented 6 years ago

Hi again, I am trying to create a menu like structure . Until now I have been using windows and groups. But it does not make to much sense to me to create multiple windows. It should be smth much more dynamically proccess. Below is the function that will create me a "MAIN MENU" window.

void create_main_window()
{
    g = lv_group_create();

    static lv_style_t win_style;
    lv_style_copy(&win_style, &lv_style_transp);
    win_style.body.padding.hor = LV_DPI / 4;
    win_style.body.padding.ver = LV_DPI / 4;
    win_style.body.padding.inner = LV_DPI / 4;
    last_win = lv_win_create(lv_scr_act(), NULL);
    lv_win_set_title(last_win, "MAIN MENU");
    lv_win_set_layout(last_win, LV_LAYOUT_PRETTY);
    lv_win_set_style(last_win, LV_WIN_STYLE_CONTENT_SCRL, &win_style);

    win_btn = lv_win_add_btn(last_win, SYMBOL_OK, NULL);
    lv_obj_set_free_num(win_btn, LV_GROUP_KEY_ENTER);
    lv_group_add_obj(g, win_btn);

    //
    btn1 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn1, true, true);
    lv_group_add_obj(g, btn1);
    lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn1, 1);

    obj = lv_label_create(btn1, NULL);
    lv_label_set_text(obj, "Menu 1");

    btn2 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn2, true, true);
    lv_group_add_obj(g, btn2);
    lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn2, 1);
    obj = lv_label_create(btn2, NULL);
    lv_label_set_text(obj, "Menu 2");

    btn3 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn3, true, true);
    lv_group_add_obj(g, btn3);
    lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn3, 1);
    obj = lv_label_create(btn3, NULL);
    lv_label_set_text(obj, "Menu 3");

    btn4 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn4, true, true);
    lv_group_add_obj(g, btn4);
    lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn4, 1);
    obj = lv_label_create(btn4, NULL);
    lv_label_set_text(obj, "Menu 4");
    /////////////////
    win=last_win;
    lv_win_focus(win, btn1, 0);
    lv_group_set_focus_cb(g, group_focus_cb);
}

And that will give a scrollable page like in the image: whatsapp image 2018-08-24 at 12 36 19 What I have done so far is that I can enter in every menu I want using function create_window(char * title)

void create_window(char * title)
{

    g = lv_group_create();
//  lv_scr_load(new_Screen);
    static lv_style_t win_style;
    lv_style_copy(&win_style, &lv_style_transp);
    win_style.body.padding.hor = LV_DPI / 4;
    win_style.body.padding.ver = LV_DPI / 4;
    win_style.body.padding.inner = LV_DPI / 4;
    last_win = lv_win_create(lv_scr_act(),NULL);
    lv_win_set_title(last_win, title);
    lv_win_set_layout(last_win, LV_LAYOUT_PRETTY);
    lv_win_set_style(last_win, LV_WIN_STYLE_CONTENT_SCRL, &win_style);

    win_btn = lv_win_add_btn(last_win, SYMBOL_OK, NULL);
    lv_obj_set_free_num(win_btn, LV_GROUP_KEY_ENTER);
    lv_group_add_obj(g, win_btn);

    exit_button = lv_win_add_btn(last_win, SYMBOL_CLOSE, exit_action);
    lv_obj_set_free_num(exit_button, LV_GROUP_KEY_ESC);
    lv_group_add_obj(g, exit_button);
    //
    btn1 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn1, true, true);
    lv_group_add_obj(g, btn1);
    lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn1, 1);

    obj = lv_label_create(btn1, NULL);
    lv_label_set_text(obj, "Menu 1");

    btn2 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn2, true, true);
    lv_group_add_obj(g, btn2);
    lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn2, 1);
    obj = lv_label_create(btn2, NULL);
    lv_label_set_text(obj, "Menu 2");

    btn3 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn3, true, true);
    lv_group_add_obj(g, btn3);
    lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn3, 1);
    obj = lv_label_create(btn3, NULL);
    lv_label_set_text(obj, "Menu 3");

    btn4 = lv_btn_create(last_win, NULL);
    lv_btn_set_fit(btn4, true, true);
    lv_group_add_obj(g, btn4);
    lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, my_click_action);
    lv_obj_set_free_num(btn4, 1);
    obj = lv_label_create(btn4, NULL);
    lv_label_set_text(obj, "Menu 4");
    /////////////////
    windows[depth_window]=win;
    depth_window++;
    win=last_win;
    lv_win_focus(win, btn1, 0);
    lv_group_set_focus_cb(g, group_focus_cb);
}

whatsapp image 2018-08-24 at 12 40 57

which is called in the my_click_action

lv_res_t my_click_action(struct _lv_obj_t * obj) {
    //  LED_Toggle();
    PRINTF("Button Clicked\n");
    lv_obj_t * parent_window=lv_obj_get_parent(obj->par->par); //parent i buttonit eshte header i window-it.
    lv_win_ext_t * ext = lv_obj_get_ext_attr(parent_window);
    PRINTF("Actual Window %s\n",lv_label_get_text(ext->title));
    lv_obj_t *label=lv_obj_get_child(obj, NULL);
    PRINTF("Pressed button %s\n",lv_label_get_text(label));
    create_window(lv_label_get_text(label));

    return LV_RES_INV;
}

Right now I am not able to go back to the previous window I had. Can you suggest a better way to handle that.

sokolbiba commented 6 years ago

Another thing that I forgot to mention to above is that every time I create a new window I save its pointer to windows[windows_depth] array. I do not know if there is a function that will make the render if I give as parameter the pointer to the window?

kisvegabor commented 6 years ago

Hi,

Menu Do you have a full keyboard or just a few buttons? Anyway, what about lv_list? https://littlevgl.com/object-types/list-lv_list

Window order If you create a new window, it will above the others. So always the new window will be visible in the foreground. If you close it the previous window will be shown.

sokolbiba commented 6 years ago

HI, Sorry for late response. I have an encoder and I am trying to navigate through the menu. Seems that https://littlevgl.com/object-types/list-lv_list could make a good combination between lv_window and lv_list.

I am trying to test the line_meter example. Seems that style_lmeter1.body.padding.hor=40; does not change the line length. I changed it to 80 then down to 20 but the line length keeps the same length. Any ide what am I missing ? Regards

kisvegabor commented 6 years ago

Hi,

I tested the lmeter with this code on the master branch:

    static lv_style_t ls;
    lv_style_copy(&ls, &lv_style_pretty_color);
    ls.body.padding.hor = 40;

    lv_obj_t * lmeter = lv_lmeter_create(lv_scr_act(), NULL);
    lv_lmeter_set_style(lmeter, &ls);

and got this: image

What is the result of the above code for you?

sokolbiba commented 6 years ago

In fact I am using the dev-5.2 branch. I did not tested it with master branch

kisvegabor commented 6 years ago

With this code it also works for me in dev-5.2

sokolbiba commented 6 years ago

I tried it on the master branch and works fine. Do not know why is not working with the dev 5.2 .

kisvegabor commented 6 years ago

Have you tried this code in dev-5.2 too?

sokolbiba commented 6 years ago

Yeah I have tried it. Have a look at the image. That happened only by switching from master to dev 5.2 whatsapp image 2018-08-28 at 14 59 34 whatsapp image 2018-08-28 at 15 06 40

sokolbiba commented 6 years ago

Here is another difference between the way that both libraries draw the line of width 4. The master branch is cutting the lines in the outer side of the "circle" at some strange angle. whatsapp image 2018-08-28 at 15 35 53 In the dev 5.2 this seems to be better. All lines in the outer side of the "circle" finish in a beauty way. whatsapp image 2018-08-28 at 15 35 27

Hope can distinguish the difference. :)

kisvegabor commented 6 years ago

Yes, I see the difference. I took me weeks to implement this line drawing algorithm which has perpendicular ending and anti-aliasing and supports opacity too :)

However, I don't know what can be the problem as it works for me.

To debug it I suggest to check lv_lmeter_design() in lv_lmeter.c. This line takes into account the padding.hor:

        lv_coord_t r_in = r_out - style->body.padding.hor;
kisvegabor commented 5 years ago

As there was no activity here for a while I close it to keep the issues clear.

If you have remarks about this topic feel free to comment here and reopen the issue.