1 /**
2 * @file lv_draw_rect.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_rect_private.h"
10 #include "lv_draw_private.h"
11 #include "../core/lv_obj.h"
12 #include "../misc/lv_assert.h"
13 #include "../core/lv_obj_event.h"
14 #include "../stdlib/lv_string.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23
24 /**********************
25 * STATIC PROTOTYPES
26 **********************/
27
28 /**********************
29 * STATIC VARIABLES
30 **********************/
31
32 /**********************
33 * MACROS
34 **********************/
35
36 /**********************
37 * GLOBAL FUNCTIONS
38 **********************/
39
lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)40 void LV_ATTRIBUTE_FAST_MEM lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
41 {
42 lv_memzero(dsc, sizeof(lv_draw_rect_dsc_t));
43 dsc->bg_color = lv_color_white();
44 dsc->bg_grad.stops[0].color = lv_color_white();
45 dsc->bg_grad.stops[1].color = lv_color_black();
46 dsc->bg_grad.stops[1].frac = 0xFF;
47 dsc->bg_grad.stops_count = 2;
48 dsc->border_color = lv_color_black();
49 dsc->shadow_color = lv_color_black();
50 dsc->bg_image_symbol_font = LV_FONT_DEFAULT;
51 dsc->bg_opa = LV_OPA_COVER;
52 dsc->bg_image_opa = LV_OPA_COVER;
53 dsc->outline_opa = LV_OPA_COVER;
54 dsc->border_opa = LV_OPA_COVER;
55 dsc->shadow_opa = LV_OPA_COVER;
56 dsc->border_side = LV_BORDER_SIDE_FULL;
57 }
58
lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)59 void lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)
60 {
61 lv_memzero(dsc, sizeof(*dsc));
62 dsc->opa = LV_OPA_COVER;
63 dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
64 }
65
lv_draw_task_get_fill_dsc(lv_draw_task_t * task)66 lv_draw_fill_dsc_t * lv_draw_task_get_fill_dsc(lv_draw_task_t * task)
67 {
68 return task->type == LV_DRAW_TASK_TYPE_FILL ? (lv_draw_fill_dsc_t *)task->draw_dsc : NULL;
69 }
70
lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)71 void lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)
72 {
73 lv_memzero(dsc, sizeof(*dsc));
74 dsc->opa = LV_OPA_COVER;
75 dsc->side = LV_BORDER_SIDE_FULL;
76 dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
77 }
78
lv_draw_task_get_border_dsc(lv_draw_task_t * task)79 lv_draw_border_dsc_t * lv_draw_task_get_border_dsc(lv_draw_task_t * task)
80 {
81 return task->type == LV_DRAW_TASK_TYPE_BORDER ? (lv_draw_border_dsc_t *)task->draw_dsc : NULL;
82 }
83
lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)84 void lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)
85 {
86 lv_memzero(dsc, sizeof(*dsc));
87 dsc->opa = LV_OPA_COVER;
88 dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
89 }
90
lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)91 lv_draw_box_shadow_dsc_t * lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)
92 {
93 return task->type == LV_DRAW_TASK_TYPE_BOX_SHADOW ? (lv_draw_box_shadow_dsc_t *)task->draw_dsc : NULL;
94 }
95
lv_draw_rect(lv_layer_t * layer,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)96 void lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
97 {
98
99 LV_PROFILER_DRAW_BEGIN;
100 bool has_shadow;
101 bool has_fill;
102 bool has_border;
103 bool has_outline;
104 bool has_bg_img;
105
106 if(dsc->shadow_width == 0 ||
107 dsc->shadow_opa <= LV_OPA_MIN ||
108 (dsc->shadow_width == 1 && dsc->shadow_spread <= 0 &&
109 dsc->shadow_offset_x == 0 && dsc->shadow_offset_y == 0)) {
110 has_shadow = false;
111 }
112 else {
113 has_shadow = true;
114 }
115
116 if(dsc->bg_opa <= LV_OPA_MIN) has_fill = false;
117 else has_fill = true;
118
119 if(dsc->bg_image_opa <= LV_OPA_MIN || dsc->bg_image_src == NULL) has_bg_img = false;
120 else has_bg_img = true;
121
122 if(dsc->border_opa <= LV_OPA_MIN
123 || dsc->border_width == 0
124 || dsc->border_post == true
125 || dsc->border_side == LV_BORDER_SIDE_NONE) has_border = false;
126 else has_border = true;
127
128 if(dsc->outline_opa <= LV_OPA_MIN || dsc->outline_width == 0) has_outline = false;
129 else has_outline = true;
130
131 bool bg_cover = true;
132 if(dsc->bg_opa < LV_OPA_COVER) bg_cover = false;
133 else if(dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
134 uint32_t s;
135 for(s = 0; s < dsc->bg_grad.stops_count; s++) {
136 if(dsc->bg_grad.stops[s].opa != LV_OPA_COVER) {
137 bg_cover = false;
138 break;
139 }
140 }
141 }
142
143 lv_draw_task_t * t;
144
145 /*Shadow*/
146 if(has_shadow) {
147 /*Check whether the shadow is visible*/
148 t = lv_draw_add_task(layer, coords);
149 lv_draw_box_shadow_dsc_t * shadow_dsc = lv_malloc(sizeof(lv_draw_box_shadow_dsc_t));
150 LV_ASSERT_MALLOC(shadow_dsc);
151 t->draw_dsc = shadow_dsc;
152 lv_area_increase(&t->_real_area, dsc->shadow_spread, dsc->shadow_spread);
153 lv_area_increase(&t->_real_area, dsc->shadow_width, dsc->shadow_width);
154 lv_area_move(&t->_real_area, dsc->shadow_offset_x, dsc->shadow_offset_y);
155 shadow_dsc->base = dsc->base;
156 shadow_dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
157 shadow_dsc->radius = dsc->radius;
158 shadow_dsc->color = dsc->shadow_color;
159 shadow_dsc->width = dsc->shadow_width;
160 shadow_dsc->spread = dsc->shadow_spread;
161 shadow_dsc->opa = dsc->shadow_opa;
162 shadow_dsc->ofs_x = dsc->shadow_offset_x;
163 shadow_dsc->ofs_y = dsc->shadow_offset_y;
164 shadow_dsc->bg_cover = bg_cover;
165 t->type = LV_DRAW_TASK_TYPE_BOX_SHADOW;
166 lv_draw_finalize_task_creation(layer, t);
167 }
168
169 /*Background*/
170 if(has_fill) {
171 lv_area_t bg_coords = *coords;
172 /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
173 if(dsc->border_width > 1 && dsc->border_opa >= LV_OPA_MAX && dsc->radius != 0) {
174 bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
175 bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
176 bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
177 bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
178 }
179
180 t = lv_draw_add_task(layer, &bg_coords);
181 lv_draw_fill_dsc_t * bg_dsc = lv_malloc(sizeof(lv_draw_fill_dsc_t));
182 LV_ASSERT_MALLOC(bg_dsc);
183 lv_draw_fill_dsc_init(bg_dsc);
184 t->draw_dsc = bg_dsc;
185 bg_dsc->base = dsc->base;
186 bg_dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
187 bg_dsc->radius = dsc->radius;
188 bg_dsc->color = dsc->bg_color;
189 bg_dsc->grad = dsc->bg_grad;
190 bg_dsc->opa = dsc->bg_opa;
191 t->type = LV_DRAW_TASK_TYPE_FILL;
192
193 lv_draw_finalize_task_creation(layer, t);
194 }
195
196 /*Background image*/
197 if(has_bg_img) {
198 lv_image_src_t src_type = lv_image_src_get_type(dsc->bg_image_src);
199 lv_result_t res = LV_RESULT_OK;
200 lv_image_header_t header;
201 if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
202 res = lv_image_decoder_get_info(dsc->bg_image_src, &header);
203 }
204 else {
205 lv_memzero(&header, sizeof(header));
206
207 if(src_type == LV_IMAGE_SRC_UNKNOWN) {
208 res = LV_RESULT_INVALID;
209 }
210 }
211
212 if(res == LV_RESULT_OK) {
213 if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
214
215 if(dsc->bg_image_tiled) {
216 t = lv_draw_add_task(layer, coords);
217 }
218 else {
219 lv_area_t a = {0, 0, header.w - 1, header.h - 1};
220 lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
221 t = lv_draw_add_task(layer, &a);
222 }
223
224 lv_draw_image_dsc_t * bg_image_dsc = lv_malloc(sizeof(lv_draw_image_dsc_t));
225 LV_ASSERT_MALLOC(bg_image_dsc);
226 lv_draw_image_dsc_init(bg_image_dsc);
227 t->draw_dsc = bg_image_dsc;
228 bg_image_dsc->base = dsc->base;
229 bg_image_dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
230 bg_image_dsc->src = dsc->bg_image_src;
231 bg_image_dsc->opa = dsc->bg_image_opa;
232 bg_image_dsc->recolor = dsc->bg_image_recolor;
233 bg_image_dsc->recolor_opa = dsc->bg_image_recolor_opa;
234 bg_image_dsc->tile = dsc->bg_image_tiled;
235 bg_image_dsc->header = header;
236 bg_image_dsc->clip_radius = dsc->radius;
237 bg_image_dsc->image_area = *coords;
238 t->type = LV_DRAW_TASK_TYPE_IMAGE;
239 lv_draw_finalize_task_creation(layer, t);
240 }
241 else {
242 lv_point_t s;
243 lv_text_get_size(&s, dsc->bg_image_src, dsc->bg_image_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
244
245 lv_area_t a = {0, 0, s.x - 1, s.y - 1};
246 lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
247 t = lv_draw_add_task(layer, &a);
248
249 lv_draw_label_dsc_t * bg_label_dsc = lv_malloc(sizeof(lv_draw_label_dsc_t));
250 LV_ASSERT_MALLOC(bg_label_dsc);
251 lv_draw_label_dsc_init(bg_label_dsc);
252 t->draw_dsc = bg_label_dsc;
253 bg_label_dsc->base = dsc->base;
254 bg_label_dsc->base.dsc_size = sizeof(lv_draw_label_dsc_t);
255 bg_label_dsc->color = dsc->bg_image_recolor;
256 bg_label_dsc->font = dsc->bg_image_symbol_font;
257 bg_label_dsc->text = dsc->bg_image_src;
258 t->type = LV_DRAW_TASK_TYPE_LABEL;
259 lv_draw_finalize_task_creation(layer, t);
260 }
261 }
262 }
263
264 /*Border*/
265 if(has_border) {
266 t = lv_draw_add_task(layer, coords);
267 lv_draw_border_dsc_t * border_dsc = lv_malloc(sizeof(lv_draw_border_dsc_t));
268 LV_ASSERT_MALLOC(border_dsc);
269 t->draw_dsc = border_dsc;
270 border_dsc->base = dsc->base;
271 border_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
272 border_dsc->radius = dsc->radius;
273 border_dsc->color = dsc->border_color;
274 border_dsc->opa = dsc->border_opa;
275 border_dsc->width = dsc->border_width;
276 border_dsc->side = dsc->border_side;
277 t->type = LV_DRAW_TASK_TYPE_BORDER;
278 lv_draw_finalize_task_creation(layer, t);
279 }
280
281 /*Outline*/
282 if(has_outline) {
283 lv_area_t outline_coords = *coords;
284 lv_area_increase(&outline_coords, dsc->outline_width + dsc->outline_pad, dsc->outline_width + dsc->outline_pad);
285 t = lv_draw_add_task(layer, &outline_coords);
286 lv_draw_border_dsc_t * outline_dsc = lv_malloc(sizeof(lv_draw_border_dsc_t));
287 LV_ASSERT_MALLOC(outline_dsc);
288 t->draw_dsc = outline_dsc;
289 lv_area_increase(&t->_real_area, dsc->outline_width, dsc->outline_width);
290 lv_area_increase(&t->_real_area, dsc->outline_pad, dsc->outline_pad);
291 outline_dsc->base = dsc->base;
292 outline_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
293 outline_dsc->radius = dsc->radius == LV_RADIUS_CIRCLE ? LV_RADIUS_CIRCLE : dsc->radius + dsc->outline_width +
294 dsc->outline_pad;
295 outline_dsc->color = dsc->outline_color;
296 outline_dsc->opa = dsc->outline_opa;
297 outline_dsc->width = dsc->outline_width;
298 outline_dsc->side = LV_BORDER_SIDE_FULL;
299 t->type = LV_DRAW_TASK_TYPE_BORDER;
300 lv_draw_finalize_task_creation(layer, t);
301 }
302
303 LV_ASSERT_MEM_INTEGRITY();
304
305 LV_PROFILER_DRAW_END;
306 }
307
308 /**********************
309 * STATIC FUNCTIONS
310 **********************/
311