diff --git a/docs/widgets/core/img.md b/docs/widgets/core/img.md index 7c537c634..f1b780dd1 100644 --- a/docs/widgets/core/img.md +++ b/docs/widgets/core/img.md @@ -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. diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c index 21a853868..260025379 100644 --- a/src/core/lv_obj_style.c +++ b/src/core/lv_obj_style.c @@ -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) { diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h index 0f4ae1f52..ab06cca97 100644 --- a/src/misc/lv_style.h +++ b/src/misc/lv_style.h @@ -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, diff --git a/src/widgets/lv_img.c b/src/widgets/lv_img.c index 950a58769..d869ae194 100644 --- a/src/widgets/lv_img.c +++ b/src/widgets/lv_img.c @@ -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); } } diff --git a/src/widgets/lv_img.h b/src/widgets/lv_img.h index f731eae91..b38055a60 100644 --- a/src/widgets/lv_img.h +++ b/src/widgets/lv_img.h @@ -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 **********************/