feat(grid): add a basic subgrid implementation
This commit is contained in:
@@ -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
|
||||||
***************
|
***************
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
tests/ref_imgs/subgrid_col.png
Normal file
BIN
tests/ref_imgs/subgrid_col.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
tests/ref_imgs/subgrid_row.png
Normal file
BIN
tests/ref_imgs/subgrid_row.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
93
tests/src/test_cases/test_grid.c
Normal file
93
tests/src/test_cases/test_grid.c
Normal 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
|
||||||
Reference in New Issue
Block a user