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