lvgl / lvgl

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

Create a round screen. #416

Closed sokolbiba closed 5 years ago

sokolbiba commented 5 years ago

Hi, I am working on a project and I need my screen do be like circle. I modified radius of the screen style to lv_style_scr.body.radius = LV_RADIUS_CIRCLE; but that does not work very well. Here is a picture of what it looks like. It is rounding only the upper part of the screen. I am using the dev 5.2 branch. 20180919_105912

kisvegabor commented 5 years ago

Hi,

What are the LV_HOR_RES and LV_VER_RESin `lv_conf.h? They should have the same value to make the screen square which can be "styled" to be a circle.

sokolbiba commented 5 years ago

Yeah, they are equal 240x240. I am trying to create a circle working are, I mean to write and draw and do everything inside the circle. Is that possible ?

kisvegabor commented 5 years ago

Oh, I've just realized what causes the issue. When the library draws the bottom part of the screen, then the internal graphics buffer (VDB) is initially fully white because it was drawn the middle part previously and the white content remains in it. But on the bottom, there is nothing to draw in the corners so the buffer remains white.

I agree with you. You should let the screen unchanged and create a simple, screen size object with circle style and create all your content on it. It is absolutely possible.

sokolbiba commented 5 years ago

So, can this object be a window with header and content?

sokolbiba commented 5 years ago

Do you have an idea why there are sometimes double focues objects in a group? Check the picture below 20180920_164716

kisvegabor commented 5 years ago

The window does not seem to be a good idea because it is designed to be rectangular. The control buttons are on the right and the title is on the left.

I've never met this "2 focus" issue yet. Can you send the source code of the GUI? If you are using groups what kind of input device do you use?

sokolbiba commented 5 years ago

So here is the source code of the GUI:

void create_circle(void)
{
    lv_obj_t * circle,*btn,*label,*img;
    lv_style_t *circle_style,*rel_style,*prs_style;
    circle=lv_obj_create(lv_scr_act(),NULL);
    lv_obj_set_size(circle, 240, 240);

    lv_style_copy(circle_style,&lv_style_pretty_color);
    lv_style_btn_rel.body.radius=LV_RADIUS_CIRCLE;
    lv_style_btn_pr.body.radius=LV_RADIUS_CIRCLE;
    circle_style->body.radius=LV_RADIUS_CIRCLE;
    lv_obj_set_style(circle, circle_style);
    lv_obj_align(circle, NULL, LV_ALIGN_CENTER, 0, 0);

    group=lv_group_create();

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_TOP_MID, 0, 0);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_UP);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_TOP_RIGHT, -30,30);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_BLUETOOTH);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_RIGHT_MID, 0, 0);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_RIGHT);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_BOTTOM_RIGHT, -30,-30);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_BATTERY_FULL);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_DOWN);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_BOTTOM_LEFT, 30,-30);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_SETTINGS);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_LEFT_MID, 0, 0);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_LEFT);

    btn=lv_btn_create(circle, NULL);
    lv_obj_set_size(btn, 60, 60);
    lv_group_add_obj(group,btn);
    lv_btn_set_style(btn, LV_BTN_STATE_REL, &lv_style_btn_rel);
    lv_btn_set_style(btn, LV_BTN_STATE_PR, &lv_style_btn_pr);
    lv_obj_align(btn, circle, LV_ALIGN_IN_TOP_LEFT, 30,30);
    img = lv_img_create(btn, NULL);
    lv_img_set_auto_size(img, true);
    lv_obj_set_click(img, false);
    lv_img_set_src(img, SYMBOL_WIFI);

    //  img=lv_imgbtn_create(circle, NULL);
    //  lv_imgbtn_set_src(img, LV_IMGBTN_STYLE_REL, SYMBOL_BELL);
    //  lv_imgbtn_set_src(img, LV_IMGBTN_STYLE_PR, SYMBOL_BELL);
    //  lv_imgbtn_set_style(img, LV_IMGBTN_STYLE_REL, &lv_style_btn_rel);
    //  lv_imgbtn_set_style(img, LV_IMGBTN_STYLE_PR, &lv_style_btn_pr);
    //  lv_group_add_obj(group,img);
    //  lv_obj_align(img, circle, LV_ALIGN_IN_LEFT_MID, 0, 0);

}```
I am using grup options and as input device I am using an rotary encoder.  As I do not know how to register an rotary encoder I am using interrupts from rotary encoder to navigate throughout the group. Below is the rotary encoder interrupt handler. 

void TPM0_IRQHandler(void) {

TPM_ClearStatusFlags(TPM0,kTPM_TimeOverflowFlag);
if(TPM_GetDirection(TPM0))
{
    PRINTF("Next element");
    lv_group_focus_next(group);
}
else
{
    PRINTF("Previous element\n");
    lv_group_focus_prev(group);
}

}



Please note that the  ``` group ```  object is an global variable.
kisvegabor commented 5 years ago

Hi,

Check the first part of the create_circle where you initialize the styles. You copy a style to a pointer which points not a not specified address. Besides styles should be static because the library saves only a pointer to them and now the styles will be "lost" if you exit from the function. Here is the corrected version which worked for me without any issues:

    lv_obj_t * circle,*btn,*label,*img;
    static lv_style_t circle_style,rel_style,prs_style;
    circle=lv_obj_create(lv_scr_act(),NULL);
    lv_obj_set_size(circle, 240, 240);

    lv_style_copy(&circle_style,&lv_style_pretty_color);
    lv_style_btn_rel.body.radius=LV_RADIUS_CIRCLE;
    lv_style_btn_pr.body.radius=LV_RADIUS_CIRCLE;
    circle_style.body.radius=LV_RADIUS_CIRCLE;
    lv_obj_set_style(circle, &circle_style);
    lv_obj_align(circle, NULL, LV_ALIGN_CENTER, 0, 0);

Does it fix your issue?

FYI: You should put the code block between ```c code block ``` to add C syntax highlight

sokolbiba commented 5 years ago

Hi, Thank you for the reply. It seems that its not the problem. I can still generate that "error" while I move the encoder. Do you think that it is related to the registration procces of the encoder device ?

kisvegabor commented 5 years ago

It just came to mind that calling LittlevGL functions from interrupt can be problematic, because if you call lv_task_handler in the main while(1) the functions calsl from the interrupt can mess up things if lv_task_handler makes something critical.

I suggest:

  1. In the interrupt save a rotation direction in a global variable. E.g. enc_dir = -1; or enc_dir = 1;
  2. Implement an indev_read function like this:

    bool enc_read(lv_indev_data_t * data)
    {
    if(enc_dir != 0) {
        data->state = LV_INDEV_STATE_PR;
        data->key = enc_dir < 0 ? LV_GROUP_KEY_LEFT : LV_GROUP_KEY_RIGHT;
        enc_dir = 0;
    } else {
        data->state = LV_INDEV_STATE_REL
    }
    
    return false;       /*No more data to read so return false*/
    }
  3. Register the read function:
    lv_indev_drv_t enc_drv;
    enc_drv.type = LV_INDEV_TYPE_KEYPAD;
    enc_drv.read = enc_read;
sokolbiba commented 5 years ago

I tried what you said but it is not working. I modified the above version to the following one and it seems better now:


bool enc_read(lv_indev_data_t * data)
{
    if(enc_dir != 0) {
        data->state = LV_INDEV_STATE_PR;
        if(enc_dir<0)
        {
            lv_group_focus_next(group);
        }
        else
        {
            lv_group_focus_prev(group);
        }
        enc_dir = 0;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    return false;       /*No more data to read so return false*/
}```
kisvegabor commented 5 years ago

I haven't tested the code above so it's possible that it's not working well :(

However, we just added a new input device type called: LV_INDEV_TYPE_ENCODER Here you can how to use like this:

bool enc_read(lv_indev_data_t * data)
{
    static int32_t last_diff = 0;
    data->enc_diff = diff - last_diff;;
    data->state = btn_state;

    last_diff = diff;

    return false;
}

...

 lv_indev_drv_t enc_drv;
 enc_drv.type = LV_INDEV_TYPE_ENCODER;
 enc_drv.read = enc_read;

Here is the releated coversation: https://github.com/littlevgl/lvgl/issues/422

kisvegabor commented 5 years ago

As there was no activity here for a while I close this issue.

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