1 /**
2 * @file lv_objmask.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_objmask.h"
10 #include "../lv_misc/lv_debug.h"
11 #include "../lv_draw/lv_draw.h"
12 #include "../lv_themes/lv_theme.h"
13
14 #if defined(LV_USE_OBJMASK) && LV_USE_OBJMASK != 0
15
16 /*********************
17 * DEFINES
18 *********************/
19 #define LV_OBJX_NAME "lv_objmask"
20
21 /**********************
22 * TYPEDEFS
23 **********************/
24
25 /**********************
26 * STATIC PROTOTYPES
27 **********************/
28 static lv_design_res_t lv_objmask_design(lv_obj_t * objmask, const lv_area_t * clip_area, lv_design_mode_t mode);
29 static lv_res_t lv_objmask_signal(lv_obj_t * objmask, lv_signal_t sign, void * param);
30 static uint16_t get_param_size(lv_draw_mask_type_t type);
31
32 /**********************
33 * STATIC VARIABLES
34 **********************/
35 static lv_signal_cb_t ancestor_signal;
36 static lv_design_cb_t ancestor_design;
37
38 /**********************
39 * MACROS
40 **********************/
41
42 /**********************
43 * GLOBAL FUNCTIONS
44 **********************/
45
46 /**
47 * Create a object mask object
48 * @param par pointer to an object, it will be the parent of the new object mask
49 * @param copy pointer to a object mask object, if not NULL then the new object will be copied from it
50 * @return pointer to the created object mask
51 */
lv_objmask_create(lv_obj_t * par,const lv_obj_t * copy)52 lv_obj_t * lv_objmask_create(lv_obj_t * par, const lv_obj_t * copy)
53 {
54 LV_LOG_TRACE("object mask create started");
55
56 /*Create the ancestor of object mask*/
57 lv_obj_t * objmask = lv_cont_create(par, copy);
58 LV_ASSERT_MEM(objmask);
59 if(objmask == NULL) return NULL;
60
61 /*Allocate the object mask type specific extended data*/
62 lv_objmask_ext_t * ext = lv_obj_allocate_ext_attr(objmask, sizeof(lv_objmask_ext_t));
63 LV_ASSERT_MEM(ext);
64 if(ext == NULL) {
65 lv_obj_del(objmask);
66 return NULL;
67 }
68
69 if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(objmask);
70 if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(objmask);
71
72 /*Initialize the allocated 'ext' */
73 _lv_ll_init(&ext->mask_ll, sizeof(lv_objmask_mask_t));
74
75 /*The signal and design functions are not copied so set them here*/
76 lv_obj_set_signal_cb(objmask, lv_objmask_signal);
77 lv_obj_set_design_cb(objmask, lv_objmask_design);
78
79 /*Init the new object mask object mask*/
80 if(copy == NULL) {
81 lv_theme_apply(objmask, LV_THEME_OBJMASK);
82
83 }
84 /*TODO: Copy an existing object mask*/
85 else {
86 /* lv_objmask_ext_t * copy_ext = lv_obj_get_ext_attr(copy); */
87
88 /*Refresh the style with new signal function*/
89 lv_obj_refresh_style(objmask, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
90 }
91
92 LV_LOG_INFO("object mask created");
93
94 return objmask;
95 }
96
97 /*======================
98 * Add/remove functions
99 *=====================*/
100
101 /**
102 * Add a mask
103 * @param objmask pointer to an Object mask object
104 * @param param an initialized mask parameter
105 * @return pointer to the added mask
106 */
lv_objmask_add_mask(lv_obj_t * objmask,void * param)107 lv_objmask_mask_t * lv_objmask_add_mask(lv_obj_t * objmask, void * param)
108 {
109 LV_ASSERT_OBJ(objmask, LV_OBJX_NAME);
110 LV_ASSERT_NULL(param);
111
112 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
113
114 lv_draw_mask_common_dsc_t * dsc = param;
115 uint16_t param_size = get_param_size(dsc->type);
116
117 lv_objmask_mask_t * m = _lv_ll_ins_head(&ext->mask_ll);
118 LV_ASSERT_MEM(m);
119 if(m == NULL) return NULL;
120 m->param = lv_mem_alloc(param_size);
121 LV_ASSERT_MEM(m->param);
122 if(m->param == NULL) return NULL;
123
124 _lv_memcpy(m->param, param, param_size);
125
126 lv_obj_invalidate(objmask);
127
128 return m;
129 }
130
131 /**
132 * Update an already created mask
133 * @param objmask pointer to an Object mask object
134 * @param mask pointer to created mask (returned by `lv_objmask_add_mask`)
135 * @param param an initialized mask parameter (initialized by `lv_draw_mask_line/angle/.../_init`)
136 */
lv_objmask_update_mask(lv_obj_t * objmask,lv_objmask_mask_t * mask,void * param)137 void lv_objmask_update_mask(lv_obj_t * objmask, lv_objmask_mask_t * mask, void * param)
138 {
139 LV_ASSERT_OBJ(objmask, LV_OBJX_NAME);
140 LV_ASSERT_NULL(mask);
141 LV_ASSERT_NULL(param);
142 lv_draw_mask_common_dsc_t * dsc = param;
143
144 memcpy(mask->param, param, get_param_size(dsc->type));
145
146 lv_obj_invalidate(objmask);
147 }
148
149 /**
150 * Remove a mask
151 * @param objmask pointer to an Object mask object
152 * @param mask pointer to created mask (returned by `lv_objmask_add_mask`)
153 * If `NULL` passed all masks will be deleted.
154 */
lv_objmask_remove_mask(lv_obj_t * objmask,lv_objmask_mask_t * mask)155 void lv_objmask_remove_mask(lv_obj_t * objmask, lv_objmask_mask_t * mask)
156 {
157 LV_ASSERT_OBJ(objmask, LV_OBJX_NAME);
158
159 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
160
161 /*Remove all masks*/
162 if(mask == NULL) {
163 lv_objmask_mask_t * m;
164 _LV_LL_READ(ext->mask_ll, m) {
165 lv_mem_free(m->param);
166 }
167
168 _lv_ll_clear(&ext->mask_ll);
169 }
170 /*Remove only the specified mask*/
171 else {
172 lv_mem_free(mask->param);
173 _lv_ll_remove(&ext->mask_ll, mask);
174 lv_mem_free(mask);
175 }
176
177 lv_obj_invalidate(objmask);
178 }
179
180
181
182 /*=====================
183 * Setter functions
184 *====================*/
185
186
187 /*=====================
188 * Getter functions
189 *====================*/
190
191
192 /*=====================
193 * Other functions
194 *====================*/
195
196 /**********************
197 * STATIC FUNCTIONS
198 **********************/
199
200 /**
201 * Handle the drawing related tasks of the object masks
202 * @param objmask pointer to an object
203 * @param clip_area the object will be drawn only in this area
204 * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
205 * (return 'true' if yes)
206 * LV_DESIGN_DRAW: draw the object (always return 'true')
207 * LV_DESIGN_DRAW_POST: drawing after every children are drawn
208 * @param return an element of `lv_design_res_t`
209 */
lv_objmask_design(lv_obj_t * objmask,const lv_area_t * clip_area,lv_design_mode_t mode)210 static lv_design_res_t lv_objmask_design(lv_obj_t * objmask, const lv_area_t * clip_area, lv_design_mode_t mode)
211 {
212 /*Return false if the object is not covers the mask_p area*/
213 if(mode == LV_DESIGN_COVER_CHK) {
214 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
215 if(_lv_ll_get_len(&ext->mask_ll) > 0) return LV_DESIGN_RES_MASKED;
216 else return ancestor_design(objmask, clip_area, mode);
217 }
218 /*Draw the object*/
219 else if(mode == LV_DESIGN_DRAW_MAIN) {
220 ancestor_design(objmask, clip_area, mode);
221
222 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
223
224 lv_coord_t xofs = objmask->coords.x1;
225 lv_coord_t yofs = objmask->coords.y1;
226
227 lv_objmask_mask_t * m;
228
229 _LV_LL_READ(ext->mask_ll, m) {
230 lv_draw_mask_common_dsc_t * dsc = m->param;
231
232 if(dsc->type == LV_DRAW_MASK_TYPE_LINE) {
233 lv_draw_mask_line_param_t * p_ori = m->param;
234 lv_draw_mask_line_param_t * p_new = _lv_mem_buf_get(sizeof(lv_draw_mask_line_param_t));
235
236 lv_draw_mask_line_points_init(p_new, p_ori->cfg.p1.x + xofs, p_ori->cfg.p1.y + yofs,
237 p_ori->cfg.p2.x + xofs, p_ori->cfg.p2.y + yofs,
238 p_ori->cfg.side);
239 lv_draw_mask_add(p_new, m->param);
240 }
241 else if(dsc->type == LV_DRAW_MASK_TYPE_ANGLE) {
242 lv_draw_mask_angle_param_t * p_ori = m->param;
243 lv_draw_mask_angle_param_t * p_new = _lv_mem_buf_get(sizeof(lv_draw_mask_angle_param_t));
244
245 lv_draw_mask_angle_init(p_new, p_ori->cfg.vertex_p.x + xofs, p_ori->cfg.vertex_p.y + yofs,
246 p_ori->cfg.start_angle, p_ori->cfg.end_angle);
247 lv_draw_mask_add(p_new, m->param);
248 }
249 else if(dsc->type == LV_DRAW_MASK_TYPE_RADIUS) {
250 lv_draw_mask_radius_param_t * p_ori = m->param;
251 lv_draw_mask_radius_param_t * p_new = _lv_mem_buf_get(sizeof(lv_draw_mask_radius_param_t));
252
253 lv_area_t rect;
254 rect.x1 = p_ori->cfg.rect.x1 + xofs;
255 rect.y1 = p_ori->cfg.rect.y1 + yofs;
256 rect.x2 = p_ori->cfg.rect.x2 + xofs;
257 rect.y2 = p_ori->cfg.rect.y2 + yofs;
258
259 lv_draw_mask_radius_init(p_new, &rect, p_ori->cfg.radius, p_ori->cfg.outer);
260 lv_draw_mask_add(p_new, m->param);
261 }
262 else if(dsc->type == LV_DRAW_MASK_TYPE_FADE) {
263 lv_draw_mask_fade_param_t * p_ori = m->param;
264 lv_draw_mask_fade_param_t * p_new = _lv_mem_buf_get(sizeof(lv_draw_mask_fade_param_t));
265
266 lv_area_t rect;
267 rect.x1 = p_ori->cfg.coords.x1 + xofs;
268 rect.y1 = p_ori->cfg.coords.y1 + yofs;
269 rect.x2 = p_ori->cfg.coords.x2 + xofs;
270 rect.y2 = p_ori->cfg.coords.y2 + yofs;
271
272 lv_draw_mask_fade_init(p_new, &rect, p_ori->cfg.opa_top, p_ori->cfg.y_top + yofs,
273 p_ori->cfg.opa_bottom, p_ori->cfg.y_bottom + yofs);
274 lv_draw_mask_add(p_new, m->param);
275 }
276 else if(dsc->type == LV_DRAW_MASK_TYPE_MAP) {
277 lv_draw_mask_map_param_t * p_ori = m->param;
278 lv_draw_mask_map_param_t * p_new = _lv_mem_buf_get(sizeof(lv_draw_mask_map_param_t));
279
280 lv_area_t rect;
281 rect.x1 = p_ori->cfg.coords.x1 + xofs;
282 rect.y1 = p_ori->cfg.coords.y1 + yofs;
283 rect.x2 = p_ori->cfg.coords.x2 + xofs;
284 rect.y2 = p_ori->cfg.coords.y2 + yofs;
285
286 lv_draw_mask_map_init(p_new, &rect, p_ori->cfg.map);
287 lv_draw_mask_add(p_new, m->param);
288 }
289
290
291 }
292 }
293 /*Post draw when the children are drawn*/
294 else if(mode == LV_DESIGN_DRAW_POST) {
295 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
296
297
298 lv_objmask_mask_t * m;
299
300 _LV_LL_READ(ext->mask_ll, m) {
301 void * param;
302 param = lv_draw_mask_remove_custom(m->param);
303 _lv_mem_buf_release(param);
304 }
305
306 }
307
308 return LV_DESIGN_RES_OK;
309 }
310
311 /**
312 * Signal function of the object mask
313 * @param objmask pointer to a object mask object
314 * @param sign a signal type from lv_signal_t enum
315 * @param param pointer to a signal specific variable
316 * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
317 */
lv_objmask_signal(lv_obj_t * objmask,lv_signal_t sign,void * param)318 static lv_res_t lv_objmask_signal(lv_obj_t * objmask, lv_signal_t sign, void * param)
319 {
320 lv_res_t res;
321
322 /* Include the ancient signal function */
323 res = ancestor_signal(objmask, sign, param);
324 if(res != LV_RES_OK) return res;
325 if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
326
327 if(sign == LV_SIGNAL_CLEANUP) {
328 lv_objmask_ext_t * ext = lv_obj_get_ext_attr(objmask);
329 lv_objmask_mask_t * i;
330 _LV_LL_READ(ext->mask_ll, i) {
331 if(i->param) {
332 lv_mem_free(i->param);
333 i->param = NULL;
334 }
335 }
336
337 _lv_ll_clear(&ext->mask_ll);
338 }
339
340 return res;
341 }
342
get_param_size(lv_draw_mask_type_t type)343 static uint16_t get_param_size(lv_draw_mask_type_t type)
344 {
345 uint16_t param_size;
346 switch(type) {
347 case LV_DRAW_MASK_TYPE_LINE:
348 param_size = sizeof(lv_draw_mask_line_param_t);
349 break;
350 case LV_DRAW_MASK_TYPE_ANGLE:
351 param_size = sizeof(lv_draw_mask_angle_param_t);
352 break;
353 case LV_DRAW_MASK_TYPE_RADIUS:
354 param_size = sizeof(lv_draw_mask_radius_param_t);
355 break;
356 case LV_DRAW_MASK_TYPE_FADE:
357 param_size = sizeof(lv_draw_mask_fade_param_t);
358 break;
359 case LV_DRAW_MASK_TYPE_MAP:
360 param_size = sizeof(lv_draw_mask_map_param_t);
361 break;
362 default:
363 param_size = 0;
364 }
365
366 return param_size;
367 }
368
369 #else /* Enable this file at the top */
370
371 #endif
372