feat(grid): add a basic subgrid implementation

This commit is contained in:
Gabor Kiss-Vamosi
2023-09-25 20:56:09 +02:00
parent 453235c245
commit 9c437d1073
5 changed files with 168 additions and 7 deletions

View File

@@ -5,7 +5,7 @@ Grid
Overview Overview
******** ********
The Grid layout is a subset of `CSS Flexbox <https://css-tricks.com/snippets/css/complete-guide-grid/>`__. The Grid layout is a subset of `CSS Grid <https://css-tricks.com/snippets/css/complete-guide-grid/>`__.
It can arrange items into a 2D "table" that has rows or columns It can arrange items into a 2D "table" that has rows or columns
(tracks). The item can span through multiple columns or rows. The (tracks). The item can span through multiple columns or rows. The
@@ -99,6 +99,24 @@ If there are some empty space the track can be aligned several ways:
To set the track's alignment use To set the track's alignment use
:c:expr:`lv_obj_set_grid_align(obj, column_align, row_align)`. :c:expr:`lv_obj_set_grid_align(obj, column_align, row_align)`.
Sub grid
--------
If you set the column and/or row grid descriptors of a widget to ``NULL`` it will use the grid descriptor(s) from it's parent.
For example if you create a grid item on 2..6 columns and 1..3 rows of the parent,
the grid item will see 5 columns and 4 rows with the corresponding track size from the parent.
This way even if a wrapper item is used on the grid and can be made "transparent" from the grid's point of view.
Limitations:
- The sub grid is resolved only in one level depth. That is a grid can have a sub grid children, but a sub grid can't have an other sub grid.
- ``LV_GRID_CONTENT`` tracks on the are not handled in the sub grid, only in the its own grid.
The sub grid feature works the same as in CSS. For further reference see `this description <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid>`__.
Style interface Style interface
*************** ***************

View File

@@ -180,9 +180,9 @@ static void grid_update(lv_obj_t * cont, void * user_data)
LV_LOG_INFO("update %p container", (void *)cont); LV_LOG_INFO("update %p container", (void *)cont);
LV_UNUSED(user_data); LV_UNUSED(user_data);
const lv_coord_t * col_templ = get_col_dsc(cont); // const lv_coord_t * col_templ = get_col_dsc(cont);
const lv_coord_t * row_templ = get_row_dsc(cont); // const lv_coord_t * row_templ = get_row_dsc(cont);
if(col_templ == NULL || row_templ == NULL) return; // if(col_templ == NULL || row_templ == NULL) return;
_lv_grid_calc_t c; _lv_grid_calc_t c;
calc(cont, &c); calc(cont, &c);
@@ -265,7 +265,28 @@ static void calc_free(_lv_grid_calc_t * calc)
static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * c) static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * c)
{ {
const lv_coord_t * col_templ = get_col_dsc(cont);
const lv_coord_t * col_templ;
col_templ = get_col_dsc(cont);
bool subgrid = false;
if(col_templ == NULL) {
lv_obj_t * parent = lv_obj_get_parent(cont);
col_templ = get_col_dsc(parent);
if(col_templ == NULL) {
LV_LOG_WARN("No col descriptor found even on the parent");
return;
}
lv_coord_t pos = get_col_pos(cont);
lv_coord_t span = get_col_span(cont);
lv_coord_t * col_templ_sub = lv_malloc(sizeof(lv_coord_t) * (span + 1));
lv_memcpy(col_templ_sub, &col_templ[pos], sizeof(lv_coord_t) * span);
col_templ_sub[span] = LV_GRID_TEMPLATE_LAST;
col_templ = col_templ_sub;
subgrid = true;
}
lv_coord_t cont_w = lv_obj_get_content_width(cont); lv_coord_t cont_w = lv_obj_get_content_width(cont);
c->col_num = count_tracks(col_templ); c->col_num = count_tracks(col_templ);
@@ -333,16 +354,41 @@ static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * c)
if(last_fr_i >= 0) { if(last_fr_i >= 0) {
c->w[last_fr_i] = free_w - ((free_w * (col_fr_cnt - last_fr_x)) / col_fr_cnt); c->w[last_fr_i] = free_w - ((free_w * (col_fr_cnt - last_fr_x)) / col_fr_cnt);
} }
if(subgrid) {
lv_free((void *)col_templ);
}
} }
static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * c) static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * c)
{ {
uint32_t i; const lv_coord_t * row_templ;
const lv_coord_t * row_templ = get_row_dsc(cont); row_templ = get_row_dsc(cont);
bool subgrid = false;
if(row_templ == NULL) {
lv_obj_t * parent = lv_obj_get_parent(cont);
row_templ = get_row_dsc(parent);
if(row_templ == NULL) {
LV_LOG_WARN("No row descriptor found even on the parent");
return;
}
lv_coord_t pos = get_row_pos(cont);
lv_coord_t span = get_row_span(cont);
lv_coord_t * row_templ_sub = lv_malloc(sizeof(lv_coord_t) * (span + 1));
lv_memcpy(row_templ_sub, &row_templ[pos], sizeof(lv_coord_t) * span);
row_templ_sub[span] = LV_GRID_TEMPLATE_LAST;
row_templ = row_templ_sub;
subgrid = true;
}
c->row_num = count_tracks(row_templ); c->row_num = count_tracks(row_templ);
c->y = lv_malloc(sizeof(lv_coord_t) * c->row_num); c->y = lv_malloc(sizeof(lv_coord_t) * c->row_num);
c->h = lv_malloc(sizeof(lv_coord_t) * c->row_num); c->h = lv_malloc(sizeof(lv_coord_t) * c->row_num);
/*Set sizes for CONTENT cells*/ /*Set sizes for CONTENT cells*/
uint32_t i;
for(i = 0; i < c->row_num; i++) { for(i = 0; i < c->row_num; i++) {
lv_coord_t size = LV_COORD_MIN; lv_coord_t size = LV_COORD_MIN;
if(IS_CONTENT(row_templ[i])) { if(IS_CONTENT(row_templ[i])) {
@@ -403,6 +449,10 @@ static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * c)
if(last_fr_i >= 0) { if(last_fr_i >= 0) {
c->h[last_fr_i] = free_h - ((free_h * (row_fr_cnt - last_fr_x)) / row_fr_cnt); c->h[last_fr_i] = free_h - ((free_h * (row_fr_cnt - last_fr_x)) / row_fr_cnt);
} }
if(subgrid) {
lv_free((void *)row_templ);
}
} }
/** /**

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,93 @@
#if LV_BUILD_TEST
#include "../lvgl.h"
#include "unity/unity.h"
void setUp(void)
{
/* Function run before every test */
lv_obj_clean(lv_scr_act());
}
void tearDown(void)
{
/* Function run after every test */
}
static void button_create(lv_obj_t * parent, const char * text, lv_coord_t x, lv_coord_t y)
{
lv_obj_t * btn = lv_button_create(parent);
lv_obj_set_grid_cell(btn, LV_GRID_ALIGN_STRETCH, x, 1, LV_GRID_ALIGN_STRETCH, y, 1);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, text);
lv_obj_center(label);
}
void test_subgrid_row(void)
{
const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
const lv_coord_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
lv_obj_t * cont_main = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_main, 700, 300);
lv_obj_center(cont_main);
lv_obj_set_grid_dsc_array(cont_main, col_dsc, row_dsc);
const lv_coord_t col_dsc2[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
lv_obj_t * cont_sub = lv_obj_create(cont_main);
lv_obj_set_grid_cell(cont_sub, LV_GRID_ALIGN_STRETCH, 1, 2, LV_GRID_ALIGN_STRETCH, 1, 2);
lv_obj_set_grid_dsc_array(cont_sub, col_dsc2, NULL);
lv_obj_set_style_pad_all(cont_sub, 0, 0);
button_create(cont_main, "Main 0,0", 0, 0);
button_create(cont_main, "Main 3,3", 3, 3);
button_create(cont_main, "Main 2,2", 2, 2);
button_create(cont_sub, "Sub 0,0", 0, 0);
button_create(cont_sub, "Sub 1,0", 1, 0);
button_create(cont_sub, "Sub 2,0", 2, 0);
button_create(cont_sub, "Sub 3,0", 3, 0);
button_create(cont_sub, "Sub 1,1", 1, 1);
button_create(cont_sub, "Sub 0,1", 0, 1);
TEST_ASSERT_EQUAL_SCREENSHOT("subgrid_row.png");
}
void test_subgrid_col(void)
{
const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
const lv_coord_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
lv_obj_t * cont_main = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_main, 700, 300);
lv_obj_center(cont_main);
lv_obj_set_grid_dsc_array(cont_main, col_dsc, row_dsc);
const lv_coord_t row_dsc2[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
lv_obj_t * cont_sub = lv_obj_create(cont_main);
lv_obj_set_grid_cell(cont_sub, LV_GRID_ALIGN_STRETCH, 1, 2, LV_GRID_ALIGN_STRETCH, 1, 2);
lv_obj_set_grid_dsc_array(cont_sub, NULL, row_dsc2);
lv_obj_set_style_pad_all(cont_sub, 0, 0);
button_create(cont_main, "Main 0,0", 0, 0);
button_create(cont_main, "Main 3,3", 3, 3);
button_create(cont_main, "Main 2,2", 2, 2);
button_create(cont_sub, "Sub 0,0", 0, 0);
button_create(cont_sub, "Sub 0,1", 0, 1);
button_create(cont_sub, "Sub 0,2", 0, 2);
button_create(cont_sub, "Sub 0,3", 0, 3);
button_create(cont_sub, "Sub 1,0", 1, 0);
button_create(cont_sub, "Sub 1,1", 1, 1);
TEST_ASSERT_EQUAL_SCREENSHOT("subgrid_col.png");
}
#endif