feat(obj) Backport keypad and encoder scrolling from v7 lv_page to v8 lv_obj (#2390)

* support scrolling scrollable but non-editable objects thru keypad / encoder

* update doc on `lv_obj` scrolling behavior by arrow keys
This commit is contained in:
Yin Zhong
2021-07-23 05:55:13 -07:00
committed by GitHub
parent 6d8799fbbf
commit 1f255b7a0c
4 changed files with 46 additions and 17 deletions

View File

@@ -166,7 +166,9 @@ By default, the objects can be clicked only on their coordinates, however, this
Learn more about [Events](/overview/event). Learn more about [Events](/overview/event).
## Keys ## Keys
If `LV_OBJ_FLAG_CHECKABLE` is enabled `LV_KEY_RIGHT` and `LV_KEY_UP` make the object checked, and `LV_KEY_LEFT` and `LV_KEY_DOWN` make it unchecked. If `LV_OBJ_FLAG_CHECKABLE` is enabled, `LV_KEY_RIGHT` and `LV_KEY_UP` make the object checked, and `LV_KEY_LEFT` and `LV_KEY_DOWN` make it unchecked.
If `LV_OBJ_FLAG_SCROLLABLE` is enabled, but the object is not editable (as declared by the widget class), the arrow keys (`LV_KEY_UP`, `LV_KEY_DOWN`, `LV_KEY_LEFT`, `LV_KEY_RIGHT`) scroll the object. If the object can only scroll vertically, `LV_KEY_LEFT` and `LV_KEY_RIGHT` will scroll up/down instead, making it compatible with an encoder input device. See [Input devices overview](/overview/indev) for more on encoder behaviors and the edit mode.
Learn more about [Keys](/overview/indev). Learn more about [Keys](/overview/indev).

View File

@@ -251,13 +251,7 @@ lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)
{ {
lv_obj_t * act = lv_group_get_focused(group); lv_obj_t * act = lv_group_get_focused(group);
if(act == NULL) return LV_RES_OK; if(act == NULL) return LV_RES_OK;
return lv_event_send(act, LV_EVENT_KEY, &c);
lv_res_t res;
res = lv_event_send(act, LV_EVENT_KEY, &c);
if(res != LV_RES_OK) return res;
return res;
} }
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb) void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)

View File

@@ -554,9 +554,9 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
i->proc.pr_timestamp = lv_tick_get(); i->proc.pr_timestamp = lv_tick_get();
if(data->key == LV_KEY_ENTER) { if(data->key == LV_KEY_ENTER) {
bool editable = lv_obj_is_editable(indev_obj_act); bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
if(lv_group_get_editing(g) == true || editable == false) { if(lv_group_get_editing(g) == true || editable_or_scrollable == false) {
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act); lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
if(indev_reset_check(&i->proc)) return; if(indev_reset_check(&i->proc)) return;
} }
@@ -590,12 +590,14 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
i->proc.longpr_rep_timestamp = lv_tick_get(); i->proc.longpr_rep_timestamp = lv_tick_get();
if(data->key == LV_KEY_ENTER) { if(data->key == LV_KEY_ENTER) {
bool editable = lv_obj_is_editable(indev_obj_act); bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
/*On enter long press toggle edit mode.*/ /*On enter long press toggle edit mode.*/
if(editable) { if(editable_or_scrollable) {
/*Don't leave edit mode if there is only one object (nowhere to navigate)*/ /*Don't leave edit mode if there is only one object (nowhere to navigate)*/
if(lv_group_get_obj_count(g) > 1) { if(lv_group_get_obj_count(g) > 1) {
LV_LOG_INFO("toggling edit mode");
lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/ lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); /*Remove the pressed state manually*/ lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); /*Remove the pressed state manually*/
} }
@@ -639,10 +641,11 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
LV_LOG_INFO("released"); LV_LOG_INFO("released");
if(data->key == LV_KEY_ENTER) { if(data->key == LV_KEY_ENTER) {
bool editable = lv_obj_is_editable(indev_obj_act); bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
/*The button was released on a non-editable object. Just send enter*/ /*The button was released on a non-editable object. Just send enter*/
if(editable == false) { if(editable_or_scrollable == false) {
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act); lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
if(indev_reset_check(&i->proc)) return; if(indev_reset_check(&i->proc)) return;
@@ -674,7 +677,8 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
} }
/*If the focused object is editable and now in navigate mode then on enter switch edit /*If the focused object is editable and now in navigate mode then on enter switch edit
mode*/ mode*/
else if(editable && !lv_group_get_editing(g) && !i->proc.long_pr_sent) { else if(!i->proc.long_pr_sent) {
LV_LOG_INFO("entering edit mode");
lv_group_set_editing(g, true); /*Set edit mode*/ lv_group_set_editing(g, true); /*Set edit mode*/
} }
} }
@@ -686,9 +690,9 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
/*if encoder steps or simulated steps via left/right keys*/ /*if encoder steps or simulated steps via left/right keys*/
if(data->enc_diff != 0) { if(data->enc_diff != 0) {
LV_LOG_INFO("rotated by %d", data->enc_diff);
/*In edit mode send LEFT/RIGHT keys*/ /*In edit mode send LEFT/RIGHT keys*/
if(lv_group_get_editing(g)) { if(lv_group_get_editing(g)) {
LV_LOG_INFO("rotated by %+d (edit)", data->enc_diff);
int32_t s; int32_t s;
if(data->enc_diff < 0) { if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(g, LV_KEY_LEFT); for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(g, LV_KEY_LEFT);
@@ -699,6 +703,7 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
} }
/*In navigate mode focus on the next/prev objects*/ /*In navigate mode focus on the next/prev objects*/
else { else {
LV_LOG_INFO("rotated by %+d (nav)", data->enc_diff);
int32_t s; int32_t s;
if(data->enc_diff < 0) { if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(g); for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(g);

View File

@@ -702,6 +702,34 @@ static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e)
if(res != LV_RES_OK) return; if(res != LV_RES_OK) return;
} }
} }
else if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLLABLE) && !lv_obj_is_editable(obj)) {
/*scroll by keypad or encoder*/
lv_anim_enable_t anim_enable = LV_ANIM_OFF;
lv_coord_t sl = lv_obj_get_scroll_left(obj);
lv_coord_t sr = lv_obj_get_scroll_right(obj);
char c = *((char *)lv_event_get_param(e));
if(c == LV_KEY_DOWN) {
/*use scroll_to_x/y functions to enforce scroll limits*/
lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) + lv_obj_get_height(obj) / 4, anim_enable);
}
else if(c == LV_KEY_UP) {
lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) - lv_obj_get_height(obj) / 4, anim_enable);
}
else if(c == LV_KEY_RIGHT) {
/*If the object can't be scrolled horizontally then scroll it vertically*/
if(!((lv_obj_get_scroll_dir(obj) & LV_DIR_HOR) && (sl > 0 || sr > 0)))
lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) + lv_obj_get_height(obj) / 4, anim_enable);
else
lv_obj_scroll_to_x(obj, lv_obj_get_scroll_x(obj) + lv_obj_get_width(obj) / 4, anim_enable);
}
else if(c == LV_KEY_LEFT) {
/*If the object can't be scrolled horizontally then scroll it vertically*/
if(!((lv_obj_get_scroll_dir(obj) & LV_DIR_HOR) && (sl > 0 || sr > 0)))
lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) - lv_obj_get_height(obj) / 4, anim_enable);
else
lv_obj_scroll_to_x(obj, lv_obj_get_scroll_x(obj) - lv_obj_get_width(obj) / 4, anim_enable);
}
}
} }
else if(code == LV_EVENT_FOCUSED) { else if(code == LV_EVENT_FOCUSED) {
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) { if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) {