diff --git a/lv_core/lv_indev.c b/lv_core/lv_indev.c index 756b906d5..a9c59b7be 100644 --- a/lv_core/lv_indev.c +++ b/lv_core/lv_indev.c @@ -75,6 +75,17 @@ lv_indev_t * lv_indev_get_act(void) return indev_act; } +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(lv_indev_t * indev) +{ + if(indev == NULL) return LV_INDEV_TYPE_NONE; + + return indev->driver.type; +} /** * Reset one or all input devices * @param indev pointer to an input device to reset or NULL to reset all of them @@ -162,8 +173,8 @@ void lv_indev_set_button_points(lv_indev_t * indev, lv_point_t * points) void lv_indev_get_point(lv_indev_t * indev, lv_point_t * point) { if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) { - point->x = 0; - point->y = 0; + point->x = -1; + point->y = -1; } else { point->x = indev->proc.act_point.x; point->y = indev->proc.act_point.y; diff --git a/lv_core/lv_indev.h b/lv_core/lv_indev.h index c0b5c2808..0ff4d1ebc 100644 --- a/lv_core/lv_indev.h +++ b/lv_core/lv_indev.h @@ -40,6 +40,14 @@ void lv_indev_init(void); */ lv_indev_t * lv_indev_get_act(void); + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_hal_indev_type_t lv_indev_get_type(lv_indev_t * indev); + /** * Reset one or all input devices * @param indev pointer to an input device to reset or NULL to reset all of them diff --git a/lv_core/lv_obj.c b/lv_core/lv_obj.c index 68fe51069..2d0afef6c 100644 --- a/lv_core/lv_obj.c +++ b/lv_core/lv_obj.c @@ -1479,6 +1479,20 @@ void * lv_obj_get_group(lv_obj_t * obj) { return obj->group_p; } + +/** + * Tell whether the ohe object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(lv_obj_t * obj) +{ + if(obj->group_p) { + if(lv_group_get_focused(obj->group_p) == obj) return true; + } + + return false; +} #endif /********************** diff --git a/lv_core/lv_obj.h b/lv_core/lv_obj.h index 8616c8415..00e205c23 100644 --- a/lv_core/lv_obj.h +++ b/lv_core/lv_obj.h @@ -745,6 +745,15 @@ void * lv_obj_get_free_ptr(lv_obj_t * obj); * @return the pointer to group of the object */ void * lv_obj_get_group(lv_obj_t * obj); + + +/** + * Tell whether the ohe object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(lv_obj_t * obj); + #endif diff --git a/lv_objx/lv_btnm.c b/lv_objx/lv_btnm.c index ad98475fc..fdccadb7d 100644 --- a/lv_objx/lv_btnm.c +++ b/lv_objx/lv_btnm.c @@ -585,7 +585,17 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) ext->btn_id_pr = LV_BTNM_PR_NONE; lv_obj_invalidate(btnm); } else if(sign == LV_SIGNAL_FOCUS) { +#if USE_LV_GROUP + lv_indev_t * indev = lv_indev_get_act(); + if(lv_obj_is_focused(btnm) && lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER) { + lv_point_t p; + lv_indev_get_point(indev, &p); + uint16_t btn_i = get_button_from_point(btnm, &p); + ext->btn_id_pr = btn_i; + } +#else ext->btn_id_pr = 0; +#endif lv_obj_invalidate(btnm); } else if(sign == LV_SIGNAL_CONTROLL) { char c = *((char *)param); diff --git a/lv_objx/lv_list.c b/lv_objx/lv_list.c index f5984afd5..9a4866c0d 100644 --- a/lv_objx/lv_list.c +++ b/lv_objx/lv_list.c @@ -38,6 +38,7 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param); static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param); static lv_obj_t * get_next_btn(lv_obj_t * list, lv_obj_t * prev_btn); +static lv_obj_t * get_prev_btn(lv_obj_t * list, lv_obj_t * prev_btn); static void refr_btn_width(lv_obj_t * list); /********************** @@ -49,6 +50,10 @@ static lv_signal_func_t img_signal; static lv_signal_func_t label_signal; static lv_signal_func_t ancestor_page_signal; static lv_signal_func_t ancestor_btn_signal; +#if USE_LV_GROUP +/*Used to make the last clicked button pressed (selected) when the list become focused and `click_focus == 1`*/ +static lv_obj_t * last_clicked_btn; +#endif /********************** * MACROS @@ -527,17 +532,22 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) /*Because of the possible change of horizontal and vertical padding refresh buttons width */ refr_btn_width(list); } else if(sign == LV_SIGNAL_FOCUS) { - /*Get the first button*/ - lv_obj_t * btn = NULL; - lv_obj_t * btn_prev = NULL; - btn = get_next_btn(list, btn); - while(btn != NULL) { - btn_prev = btn; - btn = get_next_btn(list, btn); - } - if(btn_prev != NULL) { - lv_btn_set_state(btn_prev, LV_BTN_STATE_PR); - } +#if USE_LV_BTN + /*Mark the last clicked button (if any) as selected because it triggered the focus*/ + if(last_clicked_btn) { + lv_btn_set_state(last_clicked_btn, LV_BTN_STATE_PR); + } else { + /*Get the first button and mark it as selected*/ + lv_obj_t * btn = get_prev_btn(list, NULL); + if(btn) lv_btn_set_state(btn, LV_BTN_STATE_PR); + + } +#else + /*Get the first button and mark it as selected*/ + lv_obj_t * btn = get_prev_btn(list, NULL); + if(btn) lv_btn_set_state(btn, LV_BTN_STATE_PR); +#endif + } else if(sign == LV_SIGNAL_DEFOCUS) { /*Get the 'pressed' button*/ lv_obj_t * btn = NULL; @@ -550,34 +560,28 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) if(btn != NULL) { lv_btn_set_state(btn, LV_BTN_STATE_REL); } + last_clicked_btn = NULL; /*button click will set if comes before focus*/ } else if(sign == LV_SIGNAL_CONTROLL) { char c = *((char *)param); if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) { - /*Get the last pressed button*/ - lv_obj_t * btn = NULL; - lv_obj_t * btn_prev = NULL; - lv_list_ext_t * ext = lv_obj_get_ext_attr(list); - btn = get_next_btn(list, btn); - while(btn != NULL) { - if(lv_btn_get_state(btn) == LV_BTN_STATE_PR) break; - btn_prev = btn; - btn = get_next_btn(list, btn); - } + /*Get the last pressed button*/ + lv_obj_t * btn = NULL; + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + btn = get_prev_btn(list, btn); + while(btn != NULL) { + if(lv_btn_get_state(btn) == LV_BTN_STATE_PR) break; + btn = get_prev_btn(list, btn); + } - /*If there is a valid "pressed" button the make the next "pressed"*/ - if(btn_prev != NULL && btn != NULL) { - lv_btn_set_state(btn, LV_BTN_STATE_REL); - lv_btn_set_state(btn_prev, LV_BTN_STATE_PR); - lv_page_focus(list, btn_prev, ext->anim_time); - } - /*If there is no "pressed" button the make the first "pressed"*/ - else { - btn = get_next_btn(list, NULL); - if(btn) { /*If there are no buttons on the list hen there is no first button*/ - lv_btn_set_state(btn, LV_BTN_STATE_PR); - lv_page_focus(list, btn, ext->anim_time); - } - } + /*If there is a valid "pressed" button the make the previous "pressed"*/ + if(btn != NULL) { + lv_obj_t * btn_prev = get_prev_btn(list, btn); + if(btn_prev != NULL) { + lv_btn_set_state(btn, LV_BTN_STATE_REL); + lv_btn_set_state(btn_prev, LV_BTN_STATE_PR); + lv_page_focus(list, btn_prev, ext->anim_time); + } + } } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) { /*Get the last pressed button*/ lv_obj_t * btn = NULL; @@ -668,6 +672,10 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para else if(s == LV_BTN_STATE_TGL_REL) lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR); } + /* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus + * to mark it as selected (pressed state)*/ + last_clicked_btn = btn; + } #endif @@ -676,10 +684,10 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para } /** - * Get the next button from list + * Get the next button from list. (Starts from the bottom button) * @param list pointer to a list object * @param prev_btn pointer to button. Search the next after it. - * @return pointer to the next button or NULL + * @return pointer to the next button or NULL when no more buttons */ static lv_obj_t * get_next_btn(lv_obj_t * list, lv_obj_t * prev_btn) { @@ -700,6 +708,32 @@ static lv_obj_t * get_next_btn(lv_obj_t * list, lv_obj_t * prev_btn) return btn; } + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +static lv_obj_t * get_prev_btn(lv_obj_t * list, lv_obj_t * prev_btn) +{ + /* Not a good practice but user can add/create objects to the lists manually. + * When getting the next button try to be sure that it is at least a button */ + + lv_obj_t * btn ; + lv_obj_t * scrl = lv_page_get_scrl(list); + + btn = lv_obj_get_child_back(scrl, prev_btn); + if(btn == NULL) return NULL; + + while(btn->signal_func != lv_list_btn_signal) { + btn = lv_obj_get_child_back(scrl, prev_btn); + if(btn == NULL) break; + } + + return btn; +} + static void refr_btn_width(lv_obj_t * list) { lv_style_t * style = lv_list_get_style(list, LV_LIST_STYLE_BG);