1 /**
2 * @file lv_img.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_image_private.h"
10 #include "../../misc/lv_area_private.h"
11 #include "../../draw/lv_draw_image_private.h"
12 #include "../../draw/lv_draw_private.h"
13 #include "../../core/lv_obj_event_private.h"
14 #include "../../core/lv_obj_class_private.h"
15 #if LV_USE_IMAGE != 0
16
17 #include "../../stdlib/lv_string.h"
18
19 /*********************
20 * DEFINES
21 *********************/
22 #define MY_CLASS (&lv_image_class)
23
24 /**********************
25 * TYPEDEFS
26 **********************/
27
28 /**********************
29 * STATIC PROTOTYPES
30 **********************/
31 static void lv_image_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
32 static void lv_image_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e);
34 static void draw_image(lv_event_t * e);
35 static void scale_update(lv_obj_t * obj, int32_t scale_x, int32_t scale_y);
36 static void update_align(lv_obj_t * obj);
37 #if LV_USE_OBJ_PROPERTY
38 static void lv_image_set_pivot_helper(lv_obj_t * obj, lv_point_t * pivot);
39 static lv_point_t lv_image_get_pivot_helper(lv_obj_t * obj);
40 #endif
41
42 #if LV_USE_OBJ_PROPERTY
43 static const lv_property_ops_t properties[] = {
44 {
45 .id = LV_PROPERTY_IMAGE_SRC,
46 .setter = lv_image_set_src,
47 .getter = lv_image_get_src,
48 },
49 {
50 .id = LV_PROPERTY_IMAGE_OFFSET_X,
51 .setter = lv_image_set_offset_x,
52 .getter = lv_image_get_offset_x,
53 },
54 {
55 .id = LV_PROPERTY_IMAGE_OFFSET_Y,
56 .setter = lv_image_set_offset_y,
57 .getter = lv_image_get_offset_y,
58 },
59 {
60 .id = LV_PROPERTY_IMAGE_ROTATION,
61 .setter = lv_image_set_rotation,
62 .getter = lv_image_get_rotation,
63 },
64 {
65 .id = LV_PROPERTY_IMAGE_PIVOT,
66 .setter = lv_image_set_pivot_helper,
67 .getter = lv_image_get_pivot_helper,
68 },
69 {
70 .id = LV_PROPERTY_IMAGE_SCALE,
71 .setter = lv_image_set_scale,
72 .getter = lv_image_get_scale,
73 },
74 {
75 .id = LV_PROPERTY_IMAGE_SCALE_X,
76 .setter = lv_image_set_scale_x,
77 .getter = lv_image_get_scale_x,
78 },
79 {
80 .id = LV_PROPERTY_IMAGE_SCALE_Y,
81 .setter = lv_image_set_scale_y,
82 .getter = lv_image_get_scale_y,
83 },
84 {
85 .id = LV_PROPERTY_IMAGE_BLEND_MODE,
86 .setter = lv_image_set_blend_mode,
87 .getter = lv_image_get_blend_mode,
88 },
89 {
90 .id = LV_PROPERTY_IMAGE_ANTIALIAS,
91 .setter = lv_image_set_antialias,
92 .getter = lv_image_get_antialias,
93 },
94 {
95 .id = LV_PROPERTY_IMAGE_INNER_ALIGN,
96 .setter = lv_image_set_inner_align,
97 .getter = lv_image_get_inner_align,
98 },
99 };
100 #endif
101
102 /**********************
103 * STATIC VARIABLES
104 **********************/
105 const lv_obj_class_t lv_image_class = {
106 .constructor_cb = lv_image_constructor,
107 .destructor_cb = lv_image_destructor,
108 .event_cb = lv_image_event,
109 .width_def = LV_SIZE_CONTENT,
110 .height_def = LV_SIZE_CONTENT,
111 .instance_size = sizeof(lv_image_t),
112 .base_class = &lv_obj_class,
113 .name = "image",
114 #if LV_USE_OBJ_PROPERTY
115 .prop_index_start = LV_PROPERTY_IMAGE_START,
116 .prop_index_end = LV_PROPERTY_IMAGE_END,
117 .properties = properties,
118 .properties_count = sizeof(properties) / sizeof(properties[0]),
119
120 #if LV_USE_OBJ_PROPERTY_NAME
121 .property_names = lv_image_property_names,
122 .names_count = sizeof(lv_image_property_names) / sizeof(lv_property_name_t),
123 #endif
124
125 #endif
126 };
127
128 /**********************
129 * MACROS
130 **********************/
131
132 /**********************
133 * GLOBAL FUNCTIONS
134 **********************/
135
lv_image_create(lv_obj_t * parent)136 lv_obj_t * lv_image_create(lv_obj_t * parent)
137 {
138 LV_LOG_INFO("begin");
139 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
140 lv_obj_class_init_obj(obj);
141 return obj;
142 }
143
144 /*=====================
145 * Setter functions
146 *====================*/
147
lv_image_set_src(lv_obj_t * obj,const void * src)148 void lv_image_set_src(lv_obj_t * obj, const void * src)
149 {
150 LV_ASSERT_OBJ(obj, MY_CLASS);
151
152 lv_obj_invalidate(obj);
153
154 lv_image_src_t src_type = lv_image_src_get_type(src);
155 lv_image_t * img = (lv_image_t *)obj;
156
157 #if LV_USE_LOG && LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO
158 switch(src_type) {
159 case LV_IMAGE_SRC_FILE:
160 LV_LOG_TRACE("`LV_IMAGE_SRC_FILE` type found");
161 break;
162 case LV_IMAGE_SRC_VARIABLE:
163 LV_LOG_TRACE("`LV_IMAGE_SRC_VARIABLE` type found");
164 break;
165 case LV_IMAGE_SRC_SYMBOL:
166 LV_LOG_TRACE("`LV_IMAGE_SRC_SYMBOL` type found");
167 break;
168 default:
169 LV_LOG_WARN("unknown type");
170 }
171 #endif
172
173 /*If the new source type is unknown free the memories of the old source*/
174 if(src_type == LV_IMAGE_SRC_UNKNOWN) {
175 LV_LOG_WARN("unknown image type");
176 if(img->src_type == LV_IMAGE_SRC_SYMBOL || img->src_type == LV_IMAGE_SRC_FILE) {
177 lv_free((void *)img->src);
178 }
179 img->src = NULL;
180 img->src_type = LV_IMAGE_SRC_UNKNOWN;
181 return;
182 }
183
184 lv_image_header_t header;
185 lv_result_t res = lv_image_decoder_get_info(src, &header);
186 if(res != LV_RESULT_OK) {
187 #if LV_USE_LOG
188 char buf[24];
189 LV_LOG_WARN("failed to get image info: %s",
190 src_type == LV_IMAGE_SRC_FILE ? (const char *)src : (lv_snprintf(buf, sizeof(buf), "%p", src), buf));
191 #endif /*LV_USE_LOG*/
192 return;
193 }
194
195 /*Save the source*/
196 if(src_type == LV_IMAGE_SRC_VARIABLE) {
197 /*If memory was allocated because of the previous `src_type` then free it*/
198 if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_SYMBOL) {
199 lv_free((void *)img->src);
200 }
201 img->src = src;
202 }
203 else if(src_type == LV_IMAGE_SRC_FILE || src_type == LV_IMAGE_SRC_SYMBOL) {
204 /*If the new and the old src are the same then it was only a refresh.*/
205 if(img->src != src) {
206 const void * old_src = NULL;
207 /*If memory was allocated because of the previous `src_type` then save its pointer and free after allocation.
208 *It's important to allocate first to be sure the new data will be on a new address.
209 *Else `img_cache` wouldn't see the change in source.*/
210 if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_SYMBOL) {
211 old_src = img->src;
212 }
213 char * new_str = lv_strdup(src);
214 LV_ASSERT_MALLOC(new_str);
215 if(new_str == NULL) return;
216 img->src = new_str;
217
218 if(old_src) lv_free((void *)old_src);
219 }
220 }
221
222 if(src_type == LV_IMAGE_SRC_SYMBOL) {
223 /*`lv_image_dsc_get_info` couldn't set the width and height of a font so set it here*/
224 const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
225 int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
226 int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
227 lv_point_t size;
228 lv_text_get_size(&size, src, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
229 header.w = size.x;
230 header.h = size.y;
231 }
232
233 img->src_type = src_type;
234 img->w = header.w;
235 img->h = header.h;
236 img->cf = header.cf;
237
238 lv_obj_refresh_self_size(obj);
239
240 update_align(obj);
241
242 /*Provide enough room for the rotated corners*/
243 if(img->rotation || img->scale_x != LV_SCALE_NONE || img->scale_y != LV_SCALE_NONE) {
244 lv_obj_refresh_ext_draw_size(obj);
245 }
246
247 lv_obj_invalidate(obj);
248 }
249
lv_image_set_offset_x(lv_obj_t * obj,int32_t x)250 void lv_image_set_offset_x(lv_obj_t * obj, int32_t x)
251 {
252 LV_ASSERT_OBJ(obj, MY_CLASS);
253
254 lv_image_t * img = (lv_image_t *)obj;
255
256 img->offset.x = x;
257 lv_obj_invalidate(obj);
258 }
259
lv_image_set_offset_y(lv_obj_t * obj,int32_t y)260 void lv_image_set_offset_y(lv_obj_t * obj, int32_t y)
261 {
262 LV_ASSERT_OBJ(obj, MY_CLASS);
263
264 lv_image_t * img = (lv_image_t *)obj;
265
266 img->offset.y = y;
267 lv_obj_invalidate(obj);
268 }
269
lv_image_set_rotation(lv_obj_t * obj,int32_t angle)270 void lv_image_set_rotation(lv_obj_t * obj, int32_t angle)
271 {
272 LV_ASSERT_OBJ(obj, MY_CLASS);
273
274 lv_image_t * img = (lv_image_t *)obj;
275 if(img->align > LV_IMAGE_ALIGN_AUTO_TRANSFORM) {
276 angle = 0;
277 }
278 else {
279 while(angle >= 3600) angle -= 3600;
280 while(angle < 0) angle += 3600;
281 }
282
283 if((uint32_t)angle == img->rotation) return;
284
285 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
286 int32_t w = lv_obj_get_width(obj);
287 int32_t h = lv_obj_get_height(obj);
288 lv_area_t a;
289 lv_point_t pivot_px;
290 lv_image_get_pivot(obj, &pivot_px);
291 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
292 a.x1 += obj->coords.x1;
293 a.y1 += obj->coords.y1;
294 a.x2 += obj->coords.x1;
295 a.y2 += obj->coords.y1;
296 lv_obj_invalidate_area(obj, &a);
297
298 img->rotation = angle;
299
300 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
301 * the whole ext draw area */
302 lv_display_t * disp = lv_obj_get_display(obj);
303 lv_display_enable_invalidation(disp, false);
304 lv_obj_refresh_ext_draw_size(obj);
305 lv_display_enable_invalidation(disp, true);
306
307 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
308 a.x1 += obj->coords.x1;
309 a.y1 += obj->coords.y1;
310 a.x2 += obj->coords.x1;
311 a.y2 += obj->coords.y1;
312 lv_obj_invalidate_area(obj, &a);
313 }
314
lv_image_set_pivot(lv_obj_t * obj,int32_t x,int32_t y)315 void lv_image_set_pivot(lv_obj_t * obj, int32_t x, int32_t y)
316 {
317 LV_ASSERT_OBJ(obj, MY_CLASS);
318
319 lv_image_t * img = (lv_image_t *)obj;
320 if(img->align > LV_IMAGE_ALIGN_AUTO_TRANSFORM) {
321 x = 0;
322 y = 0;
323 }
324
325 if(img->pivot.x == x && img->pivot.y == y) return;
326
327 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
328 int32_t w = lv_obj_get_width(obj);
329 int32_t h = lv_obj_get_height(obj);
330 lv_area_t a;
331 lv_point_t pivot_px;
332 lv_image_get_pivot(obj, &pivot_px);
333 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
334 a.x1 += obj->coords.x1;
335 a.y1 += obj->coords.y1;
336 a.x2 += obj->coords.x1;
337 a.y2 += obj->coords.y1;
338 lv_obj_invalidate_area(obj, &a);
339
340 lv_point_set(&img->pivot, x, y);
341
342 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
343 * the whole ext draw area */
344 lv_display_t * disp = lv_obj_get_display(obj);
345 lv_display_enable_invalidation(disp, false);
346 lv_obj_refresh_ext_draw_size(obj);
347 lv_display_enable_invalidation(disp, true);
348
349 lv_image_get_pivot(obj, &pivot_px);
350 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
351 a.x1 += obj->coords.x1;
352 a.y1 += obj->coords.y1;
353 a.x2 += obj->coords.x1;
354 a.y2 += obj->coords.y1;
355 lv_obj_invalidate_area(obj, &a);
356 }
357
lv_image_set_scale(lv_obj_t * obj,uint32_t zoom)358 void lv_image_set_scale(lv_obj_t * obj, uint32_t zoom)
359 {
360 LV_ASSERT_OBJ(obj, MY_CLASS);
361
362 lv_image_t * img = (lv_image_t *)obj;
363
364 /*If scale is set internally, do no overwrite it*/
365 if(img->align > LV_IMAGE_ALIGN_AUTO_TRANSFORM) return;
366
367 if(zoom == img->scale_x && zoom == img->scale_y) return;
368
369 if(zoom == 0) zoom = 1;
370
371 scale_update(obj, zoom, zoom);
372 }
373
lv_image_set_scale_x(lv_obj_t * obj,uint32_t zoom)374 void lv_image_set_scale_x(lv_obj_t * obj, uint32_t zoom)
375 {
376 LV_ASSERT_OBJ(obj, MY_CLASS);
377
378 lv_image_t * img = (lv_image_t *)obj;
379
380 /*If scale is set internally, do no overwrite it*/
381 if(img->align > LV_IMAGE_ALIGN_AUTO_TRANSFORM) return;
382
383 if(zoom == img->scale_x) return;
384
385 if(zoom == 0) zoom = 1;
386
387 scale_update(obj, zoom, img->scale_y);
388 }
389
lv_image_set_scale_y(lv_obj_t * obj,uint32_t zoom)390 void lv_image_set_scale_y(lv_obj_t * obj, uint32_t zoom)
391 {
392 LV_ASSERT_OBJ(obj, MY_CLASS);
393
394 lv_image_t * img = (lv_image_t *)obj;
395
396 /*If scale is set internally, do no overwrite it*/
397 if(img->align > LV_IMAGE_ALIGN_AUTO_TRANSFORM) return;
398
399 if(zoom == img->scale_y) return;
400
401 if(zoom == 0) zoom = 1;
402
403 scale_update(obj, img->scale_x, zoom);
404 }
405
lv_image_set_blend_mode(lv_obj_t * obj,lv_blend_mode_t blend_mode)406 void lv_image_set_blend_mode(lv_obj_t * obj, lv_blend_mode_t blend_mode)
407 {
408 LV_ASSERT_OBJ(obj, MY_CLASS);
409
410 lv_image_t * img = (lv_image_t *)obj;
411
412 /*If scale is set internally, do no overwrite it*/
413 if(img->blend_mode == blend_mode) return;
414
415 img->blend_mode = blend_mode;
416
417 lv_obj_invalidate(obj);
418 }
419
lv_image_set_antialias(lv_obj_t * obj,bool antialias)420 void lv_image_set_antialias(lv_obj_t * obj, bool antialias)
421 {
422 LV_ASSERT_OBJ(obj, MY_CLASS);
423
424 lv_image_t * img = (lv_image_t *)obj;
425 if(antialias == img->antialias) return;
426
427 img->antialias = antialias;
428 lv_obj_invalidate(obj);
429 }
430
lv_image_set_inner_align(lv_obj_t * obj,lv_image_align_t align)431 void lv_image_set_inner_align(lv_obj_t * obj, lv_image_align_t align)
432 {
433 LV_ASSERT_OBJ(obj, MY_CLASS);
434
435 lv_image_t * img = (lv_image_t *)obj;
436 if(align == img->align) return;
437
438 /*If we're removing STRETCH, reset the scale*/
439 if(img->align == LV_IMAGE_ALIGN_STRETCH) {
440 lv_image_set_scale(obj, LV_SCALE_NONE);
441 }
442
443 img->align = align;
444 update_align(obj);
445
446 lv_obj_invalidate(obj);
447 }
448
lv_image_set_bitmap_map_src(lv_obj_t * obj,const lv_image_dsc_t * src)449 void lv_image_set_bitmap_map_src(lv_obj_t * obj, const lv_image_dsc_t * src)
450 {
451 LV_ASSERT_OBJ(obj, MY_CLASS);
452 lv_image_t * img = (lv_image_t *)obj;
453 img->bitmap_mask_src = src;
454 lv_obj_invalidate(obj);
455 }
456
457 /*=====================
458 * Getter functions
459 *====================*/
460
lv_image_get_src(lv_obj_t * obj)461 const void * lv_image_get_src(lv_obj_t * obj)
462 {
463 LV_ASSERT_OBJ(obj, MY_CLASS);
464
465 lv_image_t * img = (lv_image_t *)obj;
466
467 return img->src;
468 }
469
lv_image_get_offset_x(lv_obj_t * obj)470 int32_t lv_image_get_offset_x(lv_obj_t * obj)
471 {
472 LV_ASSERT_OBJ(obj, MY_CLASS);
473
474 lv_image_t * img = (lv_image_t *)obj;
475
476 return img->offset.x;
477 }
478
lv_image_get_offset_y(lv_obj_t * obj)479 int32_t lv_image_get_offset_y(lv_obj_t * obj)
480 {
481 LV_ASSERT_OBJ(obj, MY_CLASS);
482
483 lv_image_t * img = (lv_image_t *)obj;
484
485 return img->offset.y;
486 }
487
lv_image_get_rotation(lv_obj_t * obj)488 int32_t lv_image_get_rotation(lv_obj_t * obj)
489 {
490 LV_ASSERT_OBJ(obj, MY_CLASS);
491
492 lv_image_t * img = (lv_image_t *)obj;
493
494 return img->rotation;
495 }
496
lv_image_get_pivot(lv_obj_t * obj,lv_point_t * pivot)497 void lv_image_get_pivot(lv_obj_t * obj, lv_point_t * pivot)
498 {
499 LV_ASSERT_OBJ(obj, MY_CLASS);
500
501 lv_image_t * img = (lv_image_t *)obj;
502
503 pivot->x = lv_pct_to_px(img->pivot.x, img->w);
504 pivot->y = lv_pct_to_px(img->pivot.y, img->h);
505 }
506
lv_image_get_scale(lv_obj_t * obj)507 int32_t lv_image_get_scale(lv_obj_t * obj)
508 {
509 LV_ASSERT_OBJ(obj, MY_CLASS);
510
511 lv_image_t * img = (lv_image_t *)obj;
512
513 return img->scale_x;
514 }
515
lv_image_get_scale_x(lv_obj_t * obj)516 int32_t lv_image_get_scale_x(lv_obj_t * obj)
517 {
518 LV_ASSERT_OBJ(obj, MY_CLASS);
519
520 lv_image_t * img = (lv_image_t *)obj;
521
522 return img->scale_x;
523 }
524
lv_image_get_scale_y(lv_obj_t * obj)525 int32_t lv_image_get_scale_y(lv_obj_t * obj)
526 {
527 LV_ASSERT_OBJ(obj, MY_CLASS);
528
529 lv_image_t * img = (lv_image_t *)obj;
530
531 return img->scale_y;
532 }
533
lv_image_get_blend_mode(lv_obj_t * obj)534 lv_blend_mode_t lv_image_get_blend_mode(lv_obj_t * obj)
535 {
536 LV_ASSERT_OBJ(obj, MY_CLASS);
537
538 lv_image_t * img = (lv_image_t *)obj;
539
540 return img->blend_mode;
541 }
542
lv_image_get_antialias(lv_obj_t * obj)543 bool lv_image_get_antialias(lv_obj_t * obj)
544 {
545 LV_ASSERT_OBJ(obj, MY_CLASS);
546
547 lv_image_t * img = (lv_image_t *)obj;
548
549 return img->antialias ? true : false;
550 }
551
lv_image_get_inner_align(lv_obj_t * obj)552 lv_image_align_t lv_image_get_inner_align(lv_obj_t * obj)
553 {
554 LV_ASSERT_OBJ(obj, MY_CLASS);
555
556 lv_image_t * img = (lv_image_t *)obj;
557
558 return img->align;
559 }
560
lv_image_get_bitmap_map_src(lv_obj_t * obj)561 const lv_image_dsc_t * lv_image_get_bitmap_map_src(lv_obj_t * obj)
562 {
563 LV_ASSERT_OBJ(obj, MY_CLASS);
564
565 lv_image_t * img = (lv_image_t *)obj;
566
567 return img->bitmap_mask_src;
568 }
569
570 /**********************
571 * STATIC FUNCTIONS
572 **********************/
573
lv_image_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)574 static void lv_image_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
575 {
576 LV_UNUSED(class_p);
577 LV_TRACE_OBJ_CREATE("begin");
578
579 lv_image_t * img = (lv_image_t *)obj;
580
581 img->src = NULL;
582 img->src_type = LV_IMAGE_SRC_UNKNOWN;
583 img->cf = LV_COLOR_FORMAT_UNKNOWN;
584 img->w = lv_obj_get_width(obj);
585 img->h = lv_obj_get_height(obj);
586 img->rotation = 0;
587 img->scale_x = LV_SCALE_NONE;
588 img->scale_y = LV_SCALE_NONE;
589 img->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
590 lv_point_set(&img->offset, 0, 0);
591 lv_point_set(&img->pivot, LV_PCT(50), LV_PCT(50)); /*Default pivot to image center*/
592 img->align = LV_IMAGE_ALIGN_CENTER;
593
594 lv_obj_remove_flag(obj, LV_OBJ_FLAG_CLICKABLE);
595 lv_obj_add_flag(obj, LV_OBJ_FLAG_ADV_HITTEST);
596
597 LV_TRACE_OBJ_CREATE("finished");
598 }
599
lv_image_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)600 static void lv_image_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
601 {
602 LV_UNUSED(class_p);
603 lv_image_t * img = (lv_image_t *)obj;
604 if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_SYMBOL) {
605 lv_free((void *)img->src);
606 img->src = NULL;
607 img->src_type = LV_IMAGE_SRC_UNKNOWN;
608 }
609 }
610
lv_image_event(const lv_obj_class_t * class_p,lv_event_t * e)611 static void lv_image_event(const lv_obj_class_t * class_p, lv_event_t * e)
612 {
613 LV_UNUSED(class_p);
614
615 lv_event_code_t code = lv_event_get_code(e);
616
617 /*Call the ancestor's event handler*/
618 lv_result_t res = lv_obj_event_base(MY_CLASS, e);
619 if(res != LV_RESULT_OK) return;
620
621 lv_obj_t * obj = lv_event_get_current_target(e);
622 lv_image_t * img = (lv_image_t *)obj;
623 lv_point_t pivot_px;
624 lv_image_get_pivot(obj, &pivot_px);
625
626 if(code == LV_EVENT_STYLE_CHANGED) {
627 /*Refresh the file name to refresh the symbol text size*/
628 if(img->src_type == LV_IMAGE_SRC_SYMBOL) {
629 lv_image_set_src(obj, img->src);
630 }
631 else {
632 /*With transformation it might change*/
633 lv_obj_refresh_ext_draw_size(obj);
634 }
635 }
636 else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
637
638 int32_t * s = lv_event_get_param(e);
639
640 /*If the image has angle provide enough room for the rotated corners*/
641 if(img->rotation || img->scale_x != LV_SCALE_NONE || img->scale_y != LV_SCALE_NONE) {
642 lv_area_t a;
643 int32_t w = lv_obj_get_width(obj);
644 int32_t h = lv_obj_get_height(obj);
645 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
646 *s = LV_MAX(*s, -a.x1);
647 *s = LV_MAX(*s, -a.y1);
648 *s = LV_MAX(*s, a.x2 - w);
649 *s = LV_MAX(*s, a.y2 - h);
650 }
651 }
652 else if(code == LV_EVENT_HIT_TEST) {
653 lv_hit_test_info_t * info = lv_event_get_param(e);
654
655 /*If the object is exactly image sized (not cropped, not mosaic) and transformed
656 *perform hit test on its transformed area*/
657 if(img->w == lv_obj_get_width(obj) && img->h == lv_obj_get_height(obj) &&
658 (img->scale_x != LV_SCALE_NONE || img->scale_y != LV_SCALE_NONE ||
659 img->rotation != 0 || img->pivot.x != img->w / 2 || img->pivot.y != img->h / 2)) {
660
661 int32_t w = lv_obj_get_width(obj);
662 int32_t h = lv_obj_get_height(obj);
663 lv_area_t coords;
664 lv_image_buf_get_transformed_area(&coords, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
665 coords.x1 += obj->coords.x1;
666 coords.y1 += obj->coords.y1;
667 coords.x2 += obj->coords.x1;
668 coords.y2 += obj->coords.y1;
669
670 info->res = lv_area_is_point_on(&coords, info->point, 0);
671 }
672 else {
673 lv_area_t a;
674 lv_obj_get_click_area(obj, &a);
675 info->res = lv_area_is_point_on(&a, info->point, 0);
676 }
677 }
678 else if(code == LV_EVENT_GET_SELF_SIZE) {
679 lv_point_t * p = lv_event_get_param(e);
680 p->x = img->w;
681 p->y = img->h;
682 }
683 else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) {
684 draw_image(e);
685 }
686 }
687
draw_image(lv_event_t * e)688 static void draw_image(lv_event_t * e)
689 {
690 lv_event_code_t code = lv_event_get_code(e);
691 lv_obj_t * obj = lv_event_get_current_target(e);
692 lv_image_t * img = (lv_image_t *)obj;
693 if(code == LV_EVENT_COVER_CHECK) {
694 lv_cover_check_info_t * info = lv_event_get_param(e);
695 if(info->res == LV_COVER_RES_MASKED) return;
696 if(img->src_type == LV_IMAGE_SRC_UNKNOWN || img->src_type == LV_IMAGE_SRC_SYMBOL) {
697 info->res = LV_COVER_RES_NOT_COVER;
698 return;
699 }
700
701 /*Non true color format might have "holes"*/
702 if(lv_color_format_has_alpha(img->cf)) {
703 info->res = LV_COVER_RES_NOT_COVER;
704 return;
705 }
706
707 /*With not LV_OPA_COVER images can't cover an area */
708 if(lv_obj_get_style_image_opa(obj, LV_PART_MAIN) != LV_OPA_COVER) {
709 info->res = LV_COVER_RES_NOT_COVER;
710 return;
711 }
712
713 if(img->rotation != 0) {
714 info->res = LV_COVER_RES_NOT_COVER;
715 return;
716 }
717
718 if(img->scale_x == LV_SCALE_NONE && img->scale_y == LV_SCALE_NONE) {
719 if(lv_area_is_in(info->area, &obj->coords, 0) == false) {
720 info->res = LV_COVER_RES_NOT_COVER;
721 return;
722 }
723 }
724 else {
725 lv_area_t a;
726 lv_point_t pivot_px;
727 lv_image_get_pivot(obj, &pivot_px);
728 lv_image_buf_get_transformed_area(&a, lv_obj_get_width(obj), lv_obj_get_height(obj), 0, img->scale_x, img->scale_y,
729 &pivot_px);
730 a.x1 += obj->coords.x1;
731 a.y1 += obj->coords.y1;
732 a.x2 += obj->coords.x1;
733 a.y2 += obj->coords.y1;
734
735 if(lv_area_is_in(info->area, &a, 0) == false) {
736 info->res = LV_COVER_RES_NOT_COVER;
737 return;
738 }
739 }
740 if(img->bitmap_mask_src) {
741 info->res = LV_COVER_RES_NOT_COVER;
742 return;
743 }
744 }
745 else if(code == LV_EVENT_DRAW_MAIN) {
746
747 if(img->h == 0 || img->w == 0) return;
748 if(img->scale_x == 0 || img->scale_y == 0) return;
749
750 lv_layer_t * layer = lv_event_get_layer(e);
751
752 if(img->src_type == LV_IMAGE_SRC_FILE || img->src_type == LV_IMAGE_SRC_VARIABLE) {
753 lv_draw_image_dsc_t draw_dsc;
754 lv_draw_image_dsc_init(&draw_dsc);
755 draw_dsc.base.layer = layer;
756 lv_obj_init_draw_image_dsc(obj, LV_PART_MAIN, &draw_dsc);
757
758 lv_area_t clip_area_ori = layer->_clip_area;
759
760 lv_image_get_pivot(obj, &draw_dsc.pivot);
761 draw_dsc.scale_x = img->scale_x;
762 draw_dsc.scale_y = img->scale_y;
763 draw_dsc.rotation = img->rotation;
764 draw_dsc.antialias = img->antialias;
765 draw_dsc.blend_mode = img->blend_mode;
766 draw_dsc.bitmap_mask_src = img->bitmap_mask_src;
767 draw_dsc.src = img->src;
768
769 lv_area_set(&draw_dsc.image_area, obj->coords.x1,
770 obj->coords.y1,
771 obj->coords.x1 + img->w - 1,
772 obj->coords.y1 + img->h - 1);
773
774 draw_dsc.clip_radius = lv_obj_get_style_radius(obj, LV_PART_MAIN);
775
776 lv_area_t coords;
777 if(img->align < LV_IMAGE_ALIGN_AUTO_TRANSFORM) {
778 lv_area_align(&obj->coords, &draw_dsc.image_area, img->align, img->offset.x, img->offset.y);
779 coords = draw_dsc.image_area;
780 }
781 else if(img->align == LV_IMAGE_ALIGN_TILE) {
782 lv_area_intersect(&layer->_clip_area, &layer->_clip_area, &obj->coords);
783 lv_area_move(&draw_dsc.image_area, img->offset.x, img->offset.y);
784
785 lv_area_move(&draw_dsc.image_area,
786 ((layer->_clip_area.x1 - draw_dsc.image_area.x1 - (img->w - 1)) / img->w) * img->w,
787 ((layer->_clip_area.y1 - draw_dsc.image_area.y1 - (img->h - 1)) / img->h) * img->h);
788 coords = layer->_clip_area;
789 draw_dsc.tile = 1;
790 }
791 else {
792 coords = draw_dsc.image_area;
793 }
794
795 lv_draw_image(layer, &draw_dsc, &coords);
796 layer->_clip_area = clip_area_ori;
797
798 }
799 else if(img->src_type == LV_IMAGE_SRC_SYMBOL) {
800 lv_draw_label_dsc_t label_dsc;
801 lv_draw_label_dsc_init(&label_dsc);
802 label_dsc.base.layer = layer;
803 lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc);
804 label_dsc.text = img->src;
805 lv_draw_label(layer, &label_dsc, &obj->coords);
806 }
807 else if(img->src == NULL) {
808 /*Do not need to draw image when src is NULL*/
809 LV_LOG_WARN("image source is NULL");
810 }
811 else {
812 /*Trigger the error handler of image draw*/
813 LV_LOG_WARN("image source type is unknown");
814 }
815 }
816 }
817
scale_update(lv_obj_t * obj,int32_t scale_x,int32_t scale_y)818 static void scale_update(lv_obj_t * obj, int32_t scale_x, int32_t scale_y)
819 {
820 lv_image_t * img = (lv_image_t *)obj;
821
822 lv_obj_update_layout(obj); /*Be sure the object's size is calculated*/
823 int32_t w = lv_obj_get_width(obj);
824 int32_t h = lv_obj_get_height(obj);
825 lv_area_t a;
826 lv_point_t pivot_px;
827 lv_image_get_pivot(obj, &pivot_px);
828 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
829 a.x1 += obj->coords.x1 - 1;
830 a.y1 += obj->coords.y1 - 1;
831 a.x2 += obj->coords.x1 + 1;
832 a.y2 += obj->coords.y1 + 1;
833 lv_obj_invalidate_area(obj, &a);
834
835 img->scale_x = scale_x;
836 img->scale_y = scale_y;
837
838 /* Disable invalidations because lv_obj_refresh_ext_draw_size would invalidate
839 * the whole ext draw area */
840 lv_display_t * disp = lv_obj_get_display(obj);
841 lv_display_enable_invalidation(disp, false);
842 lv_obj_refresh_ext_draw_size(obj);
843 lv_display_enable_invalidation(disp, true);
844
845 lv_image_buf_get_transformed_area(&a, w, h, img->rotation, img->scale_x, img->scale_y, &pivot_px);
846 a.x1 += obj->coords.x1 - 1;
847 a.y1 += obj->coords.y1 - 1;
848 a.x2 += obj->coords.x1 + 1;
849 a.y2 += obj->coords.y1 + 1;
850 lv_obj_invalidate_area(obj, &a);
851 }
852
update_align(lv_obj_t * obj)853 static void update_align(lv_obj_t * obj)
854 {
855 lv_image_t * img = (lv_image_t *)obj;
856 if(img->align == LV_IMAGE_ALIGN_STRETCH) {
857 lv_image_set_rotation(obj, 0);
858 lv_image_set_pivot(obj, 0, 0);
859 if(img->w != 0 && img->h != 0) {
860 lv_obj_update_layout(obj);
861 int32_t scale_x = lv_obj_get_width(obj) * LV_SCALE_NONE / img->w;
862 int32_t scale_y = lv_obj_get_height(obj) * LV_SCALE_NONE / img->h;
863 scale_update(obj, scale_x, scale_y);
864 }
865 }
866 else if(img->align == LV_IMAGE_ALIGN_TILE) {
867 lv_image_set_rotation(obj, 0);
868 lv_image_set_pivot(obj, 0, 0);
869 scale_update(obj, LV_SCALE_NONE, LV_SCALE_NONE);
870
871 }
872 }
873
874 #if LV_USE_OBJ_PROPERTY
lv_image_set_pivot_helper(lv_obj_t * obj,lv_point_t * pivot)875 static void lv_image_set_pivot_helper(lv_obj_t * obj, lv_point_t * pivot)
876 {
877 lv_image_set_pivot(obj, pivot->x, pivot->y);
878 }
879
lv_image_get_pivot_helper(lv_obj_t * obj)880 static lv_point_t lv_image_get_pivot_helper(lv_obj_t * obj)
881 {
882 lv_point_t pivot;
883 lv_image_get_pivot(obj, &pivot);
884 return pivot;
885 }
886 #endif
887
888 #endif
889