[LVGL] Separate `objects` struct by screen
Is your feature request related to a problem? Please describe. I am relatively new to LVGL so I may misunderstand the workflow, please correct me if this is correct.
Currently all named widgets, or widgets used in a flow, have a pointer saved in the objects variable in screens.c. I think it would be beneficial for more complex UIs to have the widgets separated by the screen they are on
Describe the solution you'd like This could be a struct per screen containing pointers to all the widgets used in that screen.
So instead of this in screens.h:
typedef struct _objects_t {
lv_obj_t *main;
lv_obj_t *sub_page;
lv_obj_t *obj0;
lv_obj_t *mywidget1;
lv_obj_t *my_bar;
lv_obj_t *my_button;
} objects_t;
extern objects_t objects;
You would have something like this:
typedef struct _objects_t {
lv_obj_t *screen;
lv_obj_t *obj0;
lv_obj_t *mywidget1;
} main_screen_objects_t;
typedef struct _objects_t {
lv_obj_t *screen;
lv_obj_t *my_bar;
lv_obj_t *my_button;
} sub_page_screen_objects_t;
typedef struct _screens_t {
main_screen_objects_t main_screen;
sub_page_screen_objects_t sub_page_screen;
} screens_t
extern screens_t screen_objects;
Describe alternatives you've considered In my opinion this structure provides easier access to the widget pointers while not adding significant additional memory usage. However it does not keep the full parent child structure of widgets which would be even better.
TouchGFX has a good way of structuring the parent child hierachy of widgets and screens. I think the auto generated structure supports larger projects better since it directly integrates a model view presenter approach. https://support.touchgfx.com/docs/development/ui-development/software-architecture/code-structure
Would something similar be doable for this program?
I agree that currently generated code where we put all the widgets in the single structure is not ideal not only for the larger projects, but also for the user widgets. For example, here is how user widget create function looks like:
void create_user_widget_my_user_widget(lv_obj_t *parent_obj, void *flowState, int startWidgetIndex) {
lv_obj_t *obj = parent_obj;
{
lv_obj_t *parent_obj = obj;
{
// my_label
lv_obj_t *obj = lv_label_create(parent_obj);
((lv_obj_t **)&objects)[startWidgetIndex + 0] = obj;
// ...
}
{
// my_button
lv_obj_t *obj = lv_btn_create(parent_obj);
((lv_obj_t **)&objects)[startWidgetIndex + 1] = obj;
// ...
}
}
}
If we move each screen and user widget objects to separate structures, we will have this:
typedef struct {
lv_obj_t *my_label;
lv_obj_t *my_button;
} my_user_widget_objects_t;
void create_user_widget_my_user_widget(lv_obj_t *parent_obj, void *flowState, my_user_widget_objects_t *objects) {
lv_obj_t *obj = parent_obj;
{
lv_obj_t *parent_obj = obj;
{
// my_label
lv_obj_t *obj = lv_label_create(parent_obj);
objects->my_label = obj;
// ..
}
{
// my_button
lv_obj_t *obj = lv_btn_create(parent_obj);
objects->my_button = obj;
// ...
}
}
}
So, instead of:
((lv_obj_t **)&objects)[startWidgetIndex + 0] = obj;
we will have more elegant code:
objects->my_label = obj;
There are some technical difficulties:
- We need to keep backward compatibility for the old projects, created with previous versions of Studio. For that reason, we must add a new build option so you can choose between: (1) use single structure or (2) use separate structure per screen/user widget. Old projects will use former option and newly created projects will use later option by default. Of course, you will be able to choose option (2) for the old projects too, but you then need to update your code where you use
objectsvariable. - Some code inside EEZ Flow engine expects that pointers to all screen objects are stored in consecutive order in memory. Also, EEZ Flow engine in some parts gets object pointer by index. So, we must see how to change EEZ Flow engine to work with this new layout also.