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

feat(img) add img_size property (#2284)

* Fix image zooming causes unexpected object size.

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>

* fix(img) invalidate size and layout on zoom and angle change

* fix(img) not self-repeating under some zoom level.

* minor fixes and refactoring

* docs(img) add img_size

Co-authored-by: Xu Xingliang <xuxingliang@xiaomi.com>
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Neo 2021-07-17 03:05:49 +08:00 committed by GitHub
parent 33ba7225f5
commit fe461caf7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 16 deletions

View File

@ -90,7 +90,17 @@ The quality of the transformation can be adjusted with `lv_img_set_antialias(img
The transformations require the whole image to be available. Therefore indexed images (`LV_IMG_CF_INDEXED_...`), alpha only images (`LV_IMG_CF_ALPHA_...`) or images from files can not be transformed.
In other words transformations work only on true color images stored as C array, or if a custom [Image decoder](/overview/images#image-edecoder) returns the whole image.
Note that the real coordinates of image objects won't change during transformation. That is `lv_obj_get_width/height/x/y()` will return the original, non-zoomed coordinates.
Note that the real coordinates of image objects won't change during transformation. That is `lv_obj_get_width/height/x/y()` will return the original, non-zoomed coordinates.
### Size mode
By default if the image is zoom or rotated the real coordinates of the image object are not changed.
The larger content simply overflows the object's boundaries.
It also means the layouts are not affected the by the transformations.
If you need the object size to be updated to the transformed size set `lv_img_set_size_mode(img, LV_IMG_SIZE_MODE_REAL)`. (The previous mode is the default and called `LV_IMG_SIZE_MODE_VIRTUAL`).
In this case if the width/height of the object is set to `LV_SIZE_CONTENT` the object's size will be set to the zoomed and rotated size.
If an explicit size is set then the overflowing content will be cropped.
## Events
No special events are sent by image objects.

View File

@ -388,6 +388,8 @@ _lv_style_state_cmp_t _lv_obj_style_state_compare(lv_obj_t * obj, lv_state_t sta
else if(lv_style_get_prop(style, LV_STYLE_MIN_HEIGHT, &v)) layout_diff = true;
else if(lv_style_get_prop(style, LV_STYLE_MAX_HEIGHT, &v)) layout_diff = true;
else if(lv_style_get_prop(style, LV_STYLE_BORDER_WIDTH, &v)) layout_diff = true;
else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ANGLE, &v)) layout_diff = true;
else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ZOOM, &v)) layout_diff = true;
if(layout_diff) {
if(part_act == LV_PART_MAIN) {

View File

@ -132,8 +132,8 @@ typedef enum {
LV_STYLE_TRANSFORM_HEIGHT = 11 | LV_STYLE_PROP_EXT_DRAW,
LV_STYLE_TRANSLATE_X = 12 | LV_STYLE_PROP_LAYOUT_REFR | LV_STYLE_PROP_PARENT_LAYOUT_REFR,
LV_STYLE_TRANSLATE_Y = 13 | LV_STYLE_PROP_LAYOUT_REFR | LV_STYLE_PROP_PARENT_LAYOUT_REFR,
LV_STYLE_TRANSFORM_ZOOM = 14 | LV_STYLE_PROP_EXT_DRAW,
LV_STYLE_TRANSFORM_ANGLE = 15 | LV_STYLE_PROP_EXT_DRAW,
LV_STYLE_TRANSFORM_ZOOM = 14 | LV_STYLE_PROP_EXT_DRAW | LV_STYLE_PROP_LAYOUT_REFR | LV_STYLE_PROP_PARENT_LAYOUT_REFR,
LV_STYLE_TRANSFORM_ANGLE = 15 | LV_STYLE_PROP_EXT_DRAW | LV_STYLE_PROP_LAYOUT_REFR | LV_STYLE_PROP_PARENT_LAYOUT_REFR,
/*Group 1*/
LV_STYLE_PAD_TOP = 16 | LV_STYLE_PROP_LAYOUT_REFR,

View File

@ -291,6 +291,16 @@ void lv_img_set_antialias(lv_obj_t * obj, bool antialias)
lv_obj_invalidate(obj);
}
void lv_img_set_size_mode(lv_obj_t * obj, lv_img_size_mode_t mode)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_img_t * img = (lv_img_t *)obj;
if(mode == img->obj_size_mode) return;
img->obj_size_mode = mode;
lv_obj_invalidate(obj);
}
/*=====================
* Getter functions
*====================*/
@ -358,6 +368,13 @@ bool lv_img_get_antialias(lv_obj_t * obj)
return img->antialias ? true : false;
}
lv_img_size_mode_t lv_img_get_size_mode(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_img_t * img = (lv_img_t *)obj;
return img->obj_size_mode;
}
/**********************
* STATIC FUNCTIONS
**********************/
@ -381,6 +398,7 @@ static void lv_img_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
img->offset.y = 0;
img->pivot.x = 0;
img->pivot.y = 0;
img->obj_size_mode = LV_IMG_SIZE_MODE_VIRTUAL;
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(obj, LV_OBJ_FLAG_ADV_HITTEST);
@ -399,6 +417,22 @@ static void lv_img_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
}
}
static lv_point_t lv_img_get_tranformed_size(lv_obj_t* obj)
{
lv_img_t * img = (lv_img_t *)obj;
int32_t zoom_final = lv_obj_get_style_transform_zoom(obj, LV_PART_MAIN);
zoom_final = (zoom_final * img->zoom) >> 8;
int32_t angle_final = lv_obj_get_style_transform_angle(obj, LV_PART_MAIN);
angle_final += img->angle;
lv_area_t area_transform;
_lv_img_buf_get_transformed_area(&area_transform, img->w, img->h ,
angle_final, zoom_final, &img->pivot);
return (lv_point_t){lv_area_get_width(&area_transform), lv_area_get_height(&area_transform)};
}
static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e)
{
LV_UNUSED(class_p);
@ -477,9 +511,14 @@ static void lv_img_event(const lv_obj_class_t * class_p, lv_event_t * e)
}
}
else if(code == LV_EVENT_GET_SELF_SIZE) {
lv_point_t * p = lv_event_get_param(e);;
p->x = img->w;
p->y = img->h;
lv_point_t * p = lv_event_get_param(e);
if (img->obj_size_mode == LV_IMG_SIZE_MODE_REAL){
*p = lv_img_get_tranformed_size(obj);
}
else {
p->x = img->w;
p->y = img->h;
}
}
else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) {
draw_img(e);
@ -564,14 +603,21 @@ static void draw_img(lv_event_t * e)
bg_pivot.x = img->pivot.x + pleft;
bg_pivot.y = img->pivot.y + ptop;
lv_area_t bg_coords;
_lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
angle_final, zoom_final, &bg_pivot);
/*Modify the coordinates to draw the background for the rotated and scaled coordinates*/
bg_coords.x1 += obj->coords.x1;
bg_coords.y1 += obj->coords.y1;
bg_coords.x2 += obj->coords.x1;
bg_coords.y2 += obj->coords.y1;
if (img->obj_size_mode == LV_IMG_SIZE_MODE_REAL) {
/*Object size equals to transformed image size*/
lv_obj_get_coords(obj, &bg_coords);
}
else {
_lv_img_buf_get_transformed_area(&bg_coords, obj_w, obj_h,
angle_final, zoom_final, &bg_pivot);
/*Modify the coordinates to draw the background for the rotated and scaled coordinates*/
bg_coords.x1 += obj->coords.x1;
bg_coords.y1 += obj->coords.y1;
bg_coords.x2 += obj->coords.x1;
bg_coords.y2 += obj->coords.y1;
}
lv_area_t ori_coords;
lv_area_copy(&ori_coords, &obj->coords);
@ -590,6 +636,20 @@ static void draw_img(lv_event_t * e)
lv_area_t img_max_area;
lv_area_copy(&img_max_area, &obj->coords);
lv_point_t img_size_final = lv_img_get_tranformed_size(obj);
if(img->obj_size_mode == LV_IMG_SIZE_MODE_REAL){
img_max_area.x1 -= ((img->w - img_size_final.x) + 1) / 2;
img_max_area.x2 -= ((img->w - img_size_final.x) + 1) / 2;
img_max_area.y1 -= ((img->h - img_size_final.y) + 1) / 2;
img_max_area.y2 -= ((img->h - img_size_final.y) + 1) / 2;
}
else {
img_max_area.x2 = img_max_area.x1 + lv_area_get_width(&bg_coords) - 1;
img_max_area.y2 = img_max_area.y1 + lv_area_get_height(&bg_coords) - 1;
}
img_max_area.x1 += pleft;
img_max_area.y1 += ptop;
img_max_area.x2 -= pright;
@ -619,12 +679,12 @@ static void draw_img(lv_event_t * e)
if(coords_tmp.y1 > img_max_area.y1) coords_tmp.y1 -= img->h;
coords_tmp.y2 = coords_tmp.y1 + img->h - 1;
for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img->h, coords_tmp.y2 += img->h) {
for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img_size_final.y, coords_tmp.y2 += img_size_final.y) {
coords_tmp.x1 = img_max_area.x1 + img->offset.x;
if(coords_tmp.x1 > img_max_area.x1) coords_tmp.x1 -= img->w;
coords_tmp.x2 = coords_tmp.x1 + img->w - 1;
for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img->w, coords_tmp.x2 += img->w) {
for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img_size_final.x, coords_tmp.x2 += img_size_final.x) {
lv_draw_img(&coords_tmp, &img_clip_area, img->src, &img_dsc);
}
}

View File

@ -28,7 +28,10 @@ extern "C" {
/**********************
* TYPEDEFS
**********************/
/*Data of image*/
/**
* Data of image
*/
typedef struct {
lv_obj_t obj;
const void * src; /*Image source: Pointer to an array or a file or a symbol*/
@ -41,10 +44,28 @@ typedef struct {
uint8_t src_type : 2; /*See: lv_img_src_t*/
uint8_t cf : 5; /*Color format from `lv_img_color_format_t`*/
uint8_t antialias : 1; /*Apply anti-aliasing in transformations (rotate, zoom)*/
uint8_t obj_size_mode: 2; /*Image size mode when image size and object size is different.*/
} lv_img_t;
extern const lv_obj_class_t lv_img_class;
/**
* Image size mode, when image size and object size is different
*/
enum {
/** Zoom doesn't affect the coordinates of the object,
* however if zoomed in the image is drawn out of the its coordinates.
* The layout's won't change on zoom */
LV_IMG_SIZE_MODE_VIRTUAL = 0,
/** If the object size is set to SIZE_CONTENT, then object size equals zoomed image size.
* It causes layout recalculation.
* If the object size is set explicitly the the image will be cropped if zoomed in.*/
LV_IMG_SIZE_MODE_REAL,
};
typedef uint8_t lv_img_size_mode_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
@ -123,6 +144,13 @@ void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom);
*/
void lv_img_set_antialias(lv_obj_t * obj, bool antialias);
/**
* Set the image object size mode.
*
* @param obj pointer to an image object
* @param mode the new size mode.
*/
void lv_img_set_size_mode(lv_obj_t * obj, lv_img_size_mode_t mode);
/*=====================
* Getter functions
*====================*/
@ -176,6 +204,13 @@ uint16_t lv_img_get_zoom(lv_obj_t * obj);
*/
bool lv_img_get_antialias(lv_obj_t * obj);
/**
* Get the size mode of the image
* @param obj pointer to an image object
* @return element of @ref lv_img_size_mode_t
*/
lv_img_size_mode_t lv_img_get_size_mode(lv_obj_t * obj);
/**********************
* MACROS
**********************/