1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

Merge pull request #1341 from littlevgl/improve-hittest

Implement advanced hit-testing for zoomed images
This commit is contained in:
Gabor Kiss-Vamosi 2020-01-04 21:35:25 +01:00 committed by GitHub
commit 12222469ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 8 deletions

View File

@ -2412,12 +2412,14 @@ bool lv_obj_is_focused(const lv_obj_t * obj)
*------------------*/ *------------------*/
/** /**
* Hit-test an object given a particular point in screen space. * Check if a given screen-space point is on an object's coordinates.
* @param obj object to hit-test *
* This method is intended to be used mainly by advanced hit testing algorithms to check
* whether the point is even within the object (as an optimization).
* @param obj object to check
* @param point screen-space point * @param point screen-space point
* @return true if the object is considered under the point
*/ */
bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point) { bool lv_obj_is_point_on_coords(lv_obj_t * obj, const lv_point_t * point) {
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
lv_area_t ext_area; lv_area_t ext_area;
ext_area.x1 = obj->coords.x1 - obj->ext_click_pad_hor; ext_area.x1 = obj->coords.x1 - obj->ext_click_pad_hor;
@ -2439,15 +2441,24 @@ bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point) {
#endif #endif
return false; return false;
} }
return true;
}
/**
* Hit-test an object given a particular point in screen space.
* @param obj object to hit-test
* @param point screen-space point
* @return true if the object is considered under the point
*/
bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point) {
if(obj->adv_hittest) { if(obj->adv_hittest) {
lv_hit_test_info_t hit_info; lv_hit_test_info_t hit_info;
hit_info.point = point; hit_info.point = point;
hit_info.result = true; hit_info.result = true;
obj->signal_cb(obj, LV_SIGNAL_HIT_TEST, &hit_info); obj->signal_cb(obj, LV_SIGNAL_HIT_TEST, &hit_info);
if(!hit_info.result) return hit_info.result;
return false; } else
} return lv_obj_is_point_on_coords(obj, point);
return true;
} }
/** /**

View File

@ -940,6 +940,22 @@ lv_event_cb_t lv_obj_get_event_cb(const lv_obj_t * obj);
* Other get * Other get
*-----------------*/ *-----------------*/
/**
* Check if a given screen-space point is on an object's coordinates.
*
* This method is intended to be used mainly by advanced hit testing algorithms to check
* whether the point is even within the object (as an optimization).
* @param obj object to check
* @param point screen-space point
*/
bool lv_obj_is_point_on_coords(lv_obj_t * obj, const lv_point_t * point);
/**
* Hit-test an object given a particular point in screen space.
* @param obj object to hit-test
* @param point screen-space point
* @return true if the object is considered under the point
*/
bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point); bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point);
/** /**

View File

@ -900,9 +900,14 @@ static lv_res_t lv_cpicker_signal(lv_obj_t * cpicker, lv_signal_t sign, void * p
static bool lv_cpicker_hit(lv_obj_t * cpicker, const lv_point_t * p) static bool lv_cpicker_hit(lv_obj_t * cpicker, const lv_point_t * p)
{ {
bool is_point_on_coords = lv_obj_is_point_on_coords(cpicker, p);
if(!is_point_on_coords)
return false;
lv_cpicker_ext_t * ext = (lv_cpicker_ext_t *)lv_obj_get_ext_attr(cpicker); lv_cpicker_ext_t * ext = (lv_cpicker_ext_t *)lv_obj_get_ext_attr(cpicker);
if(ext->type != LV_CPICKER_TYPE_DISC || ext->preview) if(ext->type != LV_CPICKER_TYPE_DISC || ext->preview)
return true; return true;
const lv_style_t * style_main = lv_cpicker_get_style(cpicker, LV_CPICKER_STYLE_MAIN); const lv_style_t * style_main = lv_cpicker_get_style(cpicker, LV_CPICKER_STYLE_MAIN);
lv_area_t area_mid; lv_area_t area_mid;
lv_area_copy(&area_mid, &cpicker->coords); lv_area_copy(&area_mid, &cpicker->coords);

View File

@ -97,6 +97,7 @@ lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy)
if(copy == NULL) { if(copy == NULL) {
lv_obj_set_click(new_img, false); lv_obj_set_click(new_img, false);
lv_obj_set_adv_hittest(new_img, true); /*Images have fast hit-testing*/
/* Enable auto size for non screens /* Enable auto size for non screens
* because image screens are wallpapers * because image screens are wallpapers
* and must be screen sized*/ * and must be screen sized*/
@ -590,6 +591,26 @@ static lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param)
lv_coord_t d = ds.i / 2; lv_coord_t d = ds.i / 2;
img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, d); img->ext_draw_pad = LV_MATH_MAX(img->ext_draw_pad, d);
} }
} else if(sign == LV_SIGNAL_HIT_TEST) {
lv_hit_test_info_t *info = param;
if(ext->zoom != 256 && ext->angle == 0) {
lv_coord_t origin_width = lv_area_get_width(&img->coords);
lv_coord_t origin_height = lv_area_get_height(&img->coords);
lv_coord_t scaled_width = (origin_width * ext->zoom + 255) / 256;
lv_coord_t scaled_height = (origin_height * ext->zoom + 255) / 256;
lv_coord_t width_offset = (origin_width - scaled_width) / 2;
lv_coord_t height_offset = (origin_height - scaled_height) / 2;
lv_area_t coords;
lv_area_copy(&coords, &img->coords);
coords.x1 += width_offset;
coords.x2 -= width_offset;
coords.y1 += height_offset;
coords.y2 -= height_offset;
info->result = lv_area_is_point_on(&coords, info->point, 0);
} else
info->result = lv_obj_is_point_on_coords(img, info->point);
} }
return res; return res;