mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
feat(gridnav): single axis movement flags (#6044)
This commit is contained in:
parent
94651d8620
commit
a1a909fc24
@ -52,6 +52,13 @@ To add the gridnav feature to an object use
|
||||
object can be scrolled in that direction then it will be scrolled instead of
|
||||
going to the next/previous object. If there is no more room for scrolling the
|
||||
next/previous object will be focused normally
|
||||
- :cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY`: Only use the left/right keys
|
||||
for grid navigation. Up/down key events will be sent to the focused object.
|
||||
- :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY`: Only use the up/down keys
|
||||
for grid navigation. Left/right key events will be sent to the focused object.
|
||||
|
||||
:cpp:enumerator:`LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY` and :cpp:enumerator:`LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY`
|
||||
should not be used together.
|
||||
|
||||
:cpp:expr:`lv_gridnav_remove(cont)` Removes gridnav from an object.
|
||||
|
||||
|
@ -22,3 +22,9 @@ Simple navigation on a list widget
|
||||
|
||||
.. lv_example:: others/gridnav/lv_example_gridnav_4
|
||||
:language: c
|
||||
|
||||
Grid navigation for only one axis
|
||||
---------------------------------
|
||||
|
||||
.. lv_example:: others/gridnav/lv_example_gridnav_5
|
||||
:language: c
|
||||
|
@ -29,6 +29,7 @@ void lv_example_gridnav_1(void);
|
||||
void lv_example_gridnav_2(void);
|
||||
void lv_example_gridnav_3(void);
|
||||
void lv_example_gridnav_4(void);
|
||||
void lv_example_gridnav_5(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
69
examples/others/gridnav/lv_example_gridnav_5.c
Normal file
69
examples/others/gridnav/lv_example_gridnav_5.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_USE_GRIDNAV && LV_USE_FLEX && LV_BUILD_EXAMPLES
|
||||
|
||||
static const char * opts[] = {"0\n1\n2\n3\n4\n5", "0\n1\n2\n3\n4\n5\n6\n7\n8\n9", "s\nm\nh"};
|
||||
static const int32_t opts_counts[] = {6, 10, 3};
|
||||
|
||||
static lv_obj_t * sliders[3];
|
||||
static lv_obj_t * rollers[3];
|
||||
|
||||
static void slider_key_cb(lv_event_t * e)
|
||||
{
|
||||
uint8_t i = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
||||
lv_roller_set_selected(rollers[i], lv_slider_get_value(sliders[i]), LV_ANIM_ON);
|
||||
}
|
||||
static void roller_key_cb(lv_event_t * e)
|
||||
{
|
||||
uint8_t i = (uint32_t)(uintptr_t)lv_event_get_user_data(e);
|
||||
lv_slider_set_value(sliders[i], lv_roller_get_selected(rollers[i]), LV_ANIM_ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grid navigation for only one axis
|
||||
*/
|
||||
void lv_example_gridnav_5(void)
|
||||
{
|
||||
/*It's assumed that the default group is set and
|
||||
*there is a keyboard indev*/
|
||||
|
||||
lv_group_t * group = lv_group_get_default();
|
||||
lv_obj_t * cont;
|
||||
|
||||
cont = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_size(cont, lv_pct(100), lv_pct(50));
|
||||
lv_obj_align(cont, LV_ALIGN_TOP_MID, 0, 0);
|
||||
/* only up/down keys will be used for grid navigation in this container. */
|
||||
/* left/right will be sent to the sliders */
|
||||
lv_gridnav_add(cont, LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY);
|
||||
lv_group_add_obj(group, cont);
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
lv_obj_t * slider = lv_slider_create(cont);
|
||||
lv_slider_set_range(slider, 0, opts_counts[i] - 1);
|
||||
lv_group_remove_obj(slider);
|
||||
lv_obj_set_width(slider, lv_pct(85));
|
||||
sliders[i] = slider;
|
||||
lv_obj_add_event_cb(slider, slider_key_cb, LV_EVENT_KEY, (void *)(uintptr_t)i);
|
||||
}
|
||||
|
||||
cont = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_size(cont, lv_pct(100), lv_pct(50));
|
||||
lv_obj_align(cont, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
/* only left/right keys will be used for grid navigation in this container. */
|
||||
/* up/down will be sent to the rollers */
|
||||
lv_gridnav_add(cont, LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY);
|
||||
lv_group_add_obj(group, cont);
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
lv_obj_t * roller = lv_roller_create(cont);
|
||||
lv_roller_set_options(roller, opts[i], LV_ROLLER_MODE_INFINITE);
|
||||
lv_obj_set_size(roller, lv_pct(30), lv_pct(100));
|
||||
lv_group_remove_obj(roller);
|
||||
rollers[i] = roller;
|
||||
lv_obj_add_event_cb(roller, roller_key_cb, LV_EVENT_KEY, (void *)(uintptr_t)i);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -143,7 +143,7 @@ static void gridnav_event_cb(lv_event_t * e)
|
||||
uint32_t key = lv_event_get_key(e);
|
||||
lv_obj_t * guess = NULL;
|
||||
|
||||
if(key == LV_KEY_RIGHT) {
|
||||
if(key == LV_KEY_RIGHT && !(dsc->ctrl & LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY)) {
|
||||
if((dsc->ctrl & LV_GRIDNAV_CTRL_SCROLL_FIRST) && lv_obj_has_flag(dsc->focused_obj, LV_OBJ_FLAG_SCROLLABLE) &&
|
||||
lv_obj_get_scroll_right(dsc->focused_obj) > 0) {
|
||||
int32_t d = lv_obj_get_width(dsc->focused_obj) / 4;
|
||||
@ -163,7 +163,7 @@ static void gridnav_event_cb(lv_event_t * e)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(key == LV_KEY_LEFT) {
|
||||
else if(key == LV_KEY_LEFT && !(dsc->ctrl & LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY)) {
|
||||
if((dsc->ctrl & LV_GRIDNAV_CTRL_SCROLL_FIRST) && lv_obj_has_flag(dsc->focused_obj, LV_OBJ_FLAG_SCROLLABLE) &&
|
||||
lv_obj_get_scroll_left(dsc->focused_obj) > 0) {
|
||||
int32_t d = lv_obj_get_width(dsc->focused_obj) / 4;
|
||||
@ -183,7 +183,7 @@ static void gridnav_event_cb(lv_event_t * e)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(key == LV_KEY_DOWN) {
|
||||
else if(key == LV_KEY_DOWN && !(dsc->ctrl & LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY)) {
|
||||
if((dsc->ctrl & LV_GRIDNAV_CTRL_SCROLL_FIRST) && lv_obj_has_flag(dsc->focused_obj, LV_OBJ_FLAG_SCROLLABLE) &&
|
||||
lv_obj_get_scroll_bottom(dsc->focused_obj) > 0) {
|
||||
int32_t d = lv_obj_get_height(dsc->focused_obj) / 4;
|
||||
@ -202,7 +202,7 @@ static void gridnav_event_cb(lv_event_t * e)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(key == LV_KEY_UP) {
|
||||
else if(key == LV_KEY_UP && !(dsc->ctrl & LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY)) {
|
||||
if((dsc->ctrl & LV_GRIDNAV_CTRL_SCROLL_FIRST) && lv_obj_has_flag(dsc->focused_obj, LV_OBJ_FLAG_SCROLLABLE) &&
|
||||
lv_obj_get_scroll_top(dsc->focused_obj) > 0) {
|
||||
int32_t d = lv_obj_get_height(dsc->focused_obj) / 4;
|
||||
|
@ -80,6 +80,18 @@ typedef enum {
|
||||
* If there is no more room for scrolling the next/previous object will be focused normally */
|
||||
LV_GRIDNAV_CTRL_SCROLL_FIRST = 0x2,
|
||||
|
||||
/**
|
||||
* Only use left/right keys for grid navigation. Up/down key events will be sent to the
|
||||
* focused object.
|
||||
*/
|
||||
LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY = 0x4,
|
||||
|
||||
/**
|
||||
* Only use up/down keys for grid navigation. Left/right key events will be sent to the
|
||||
* focused object.
|
||||
*/
|
||||
LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY = 0x8
|
||||
|
||||
} lv_gridnav_ctrl_t;
|
||||
|
||||
/**********************
|
||||
|
@ -90,6 +90,7 @@
|
||||
#define LV_USE_VECTOR_GRAPHIC 1
|
||||
#define LV_USE_PROFILER 1
|
||||
#define LV_PROFILER_INCLUDE "lv_profiler_builtin.h"
|
||||
#define LV_USE_GRIDNAV 1
|
||||
|
||||
#define LV_BUILD_EXAMPLES 1
|
||||
#define LV_USE_DEMO_WIDGETS 1
|
||||
|
114
tests/src/test_cases/test_gridnav.c
Normal file
114
tests/src/test_cases/test_gridnav.c
Normal file
@ -0,0 +1,114 @@
|
||||
#if LV_BUILD_TEST
|
||||
#include "../lvgl.h"
|
||||
|
||||
#include "unity/unity.h"
|
||||
#include "lv_test_indev.h"
|
||||
|
||||
static lv_obj_t * g_screen;
|
||||
static lv_group_t * g_group;
|
||||
static struct {
|
||||
bool press_happened;
|
||||
uint32_t key;
|
||||
lv_obj_t * obj;
|
||||
} g_key_data;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
g_screen = lv_screen_active();
|
||||
g_group = lv_group_create();
|
||||
g_key_data.press_happened = false;
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
lv_obj_clean(g_screen);
|
||||
lv_group_delete(g_group); /* also removes all indevs set to the group */
|
||||
}
|
||||
|
||||
static void key_event_cb(lv_event_t * e)
|
||||
{
|
||||
TEST_ASSERT_FALSE(g_key_data.press_happened);
|
||||
g_key_data.press_happened = true;
|
||||
g_key_data.key = *(uint32_t *)lv_event_get_param(e);
|
||||
g_key_data.obj = lv_event_get_target_obj(e);
|
||||
}
|
||||
|
||||
static void gridnav_one_axis_move_only(uint32_t key_grid_axis_next,
|
||||
uint32_t key_grid_axis_prev,
|
||||
uint32_t key_obj_axis_next,
|
||||
uint32_t key_obj_axis_prev,
|
||||
lv_gridnav_ctrl_t gridnav_ctrl,
|
||||
lv_flex_flow_t flex_flow)
|
||||
{
|
||||
lv_indev_set_group(lv_test_keypad_indev, g_group);
|
||||
|
||||
lv_obj_t * cont = lv_obj_create(g_screen);
|
||||
lv_obj_set_flex_flow(cont, flex_flow);
|
||||
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_size(cont, lv_pct(100), lv_pct(100));
|
||||
lv_obj_center(cont);
|
||||
lv_gridnav_add(cont, gridnav_ctrl);
|
||||
lv_group_add_obj(g_group, cont);
|
||||
lv_obj_t * objs[3];
|
||||
for(uint32_t i = 0; i < 3; i++) {
|
||||
lv_obj_t * obj = lv_obj_create(cont);
|
||||
lv_obj_create(obj); /* the obj needs a child to be focusable by gridnav */
|
||||
lv_group_remove_obj(obj);
|
||||
lv_obj_add_event_cb(obj, key_event_cb, LV_EVENT_KEY, NULL);
|
||||
objs[i] = obj;
|
||||
}
|
||||
|
||||
TEST_ASSERT(lv_obj_get_state(objs[0]) & LV_STATE_FOCUSED);
|
||||
|
||||
/* gridnav direction key moves the focus */
|
||||
lv_test_key_hit(key_grid_axis_next);
|
||||
TEST_ASSERT(lv_obj_get_state(objs[1]) & LV_STATE_FOCUSED);
|
||||
TEST_ASSERT_FALSE(g_key_data.press_happened);
|
||||
|
||||
/* non gridnav direction key does not move the focus. */
|
||||
/* the key is sent to the object instead */
|
||||
lv_test_key_hit(key_obj_axis_next);
|
||||
TEST_ASSERT(lv_obj_get_state(objs[1]) & LV_STATE_FOCUSED);
|
||||
TEST_ASSERT_TRUE(g_key_data.press_happened);
|
||||
TEST_ASSERT(g_key_data.key == key_obj_axis_next);
|
||||
TEST_ASSERT(g_key_data.obj == objs[1]);
|
||||
g_key_data.press_happened = false;
|
||||
|
||||
lv_test_key_hit(key_obj_axis_prev);
|
||||
TEST_ASSERT(lv_obj_get_state(objs[1]) & LV_STATE_FOCUSED);
|
||||
TEST_ASSERT_TRUE(g_key_data.press_happened);
|
||||
TEST_ASSERT(g_key_data.key == key_obj_axis_prev);
|
||||
TEST_ASSERT(g_key_data.obj == objs[1]);
|
||||
g_key_data.press_happened = false;
|
||||
|
||||
/* go back */
|
||||
lv_test_key_hit(key_grid_axis_prev);
|
||||
TEST_ASSERT(lv_obj_get_state(objs[0]) & LV_STATE_FOCUSED);
|
||||
TEST_ASSERT_FALSE(g_key_data.press_happened);
|
||||
/* at the beginning, can't move further back */
|
||||
lv_test_key_hit(key_grid_axis_prev);
|
||||
TEST_ASSERT(lv_obj_get_state(objs[0]) & LV_STATE_FOCUSED);
|
||||
TEST_ASSERT_FALSE(g_key_data.press_happened);
|
||||
}
|
||||
|
||||
void test_gridnav_vertical_move_only(void)
|
||||
{
|
||||
gridnav_one_axis_move_only(LV_KEY_DOWN,
|
||||
LV_KEY_UP,
|
||||
LV_KEY_RIGHT,
|
||||
LV_KEY_LEFT,
|
||||
LV_GRIDNAV_CTRL_VERTICAL_MOVE_ONLY,
|
||||
LV_FLEX_FLOW_COLUMN);
|
||||
}
|
||||
|
||||
void test_gridnav_horizontal_move_only(void)
|
||||
{
|
||||
gridnav_one_axis_move_only(LV_KEY_RIGHT,
|
||||
LV_KEY_LEFT,
|
||||
LV_KEY_DOWN,
|
||||
LV_KEY_UP,
|
||||
LV_GRIDNAV_CTRL_HORIZONTAL_MOVE_ONLY,
|
||||
LV_FLEX_FLOW_ROW);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user