1 /**
2  * @file lv_obj_id.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj_private.h"
10 #include "../core/lv_obj.h"
11 #include "../stdlib/lv_string.h"
12 #include "../misc/lv_utils.h"
13 #include "lv_obj_property.h"
14 #include "lv_obj_class_private.h"
15 
16 #if LV_USE_OBJ_PROPERTY
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 #define HANDLE_PROPERTY_TYPE(type, field) \
23     if(!set) { \
24         value->field = ((lv_property_get_##type##_t)(prop->getter))(obj); \
25     } else { \
26         switch(LV_PROPERTY_ID_TYPE2(prop->id)) { \
27             case LV_PROPERTY_ID_INVALID: \
28                 ((lv_property_set_##type##_t)(prop->setter))(obj, value->field); \
29                 break; \
30             case LV_PROPERTY_TYPE_INT: \
31                 ((lv_property_set_##type##_integer_t)(prop->setter))(obj, value->arg1.field, value->arg2.num); \
32                 break; \
33             case LV_PROPERTY_TYPE_BOOL: \
34                 ((lv_property_set_##type##_boolean_t)(prop->setter))(obj, value->arg1.field, value->arg2.enable); \
35                 break; \
36             case LV_PROPERTY_TYPE_PRECISE: \
37                 ((lv_property_set_##type##_precise_t)(prop->setter))(obj, value->arg1.field, value->arg2.precise); \
38                 break; \
39             case LV_PROPERTY_TYPE_COLOR: \
40                 ((lv_property_set_##type##_color_t)(prop->setter))(obj, value->arg1.field, value->arg2.color); \
41                 break; \
42             case LV_PROPERTY_TYPE_POINTER: \
43             case LV_PROPERTY_TYPE_IMGSRC: \
44             case LV_PROPERTY_TYPE_TEXT: \
45             case LV_PROPERTY_TYPE_OBJ: \
46             case LV_PROPERTY_TYPE_DISPLAY: \
47             case LV_PROPERTY_TYPE_FONT: \
48                 ((lv_property_set_##type##_pointer_t)(prop->setter))(obj, value->arg1.field, value->arg2.ptr); \
49                 break; \
50         } \
51     }
52 
53 
54 /**********************
55  *      TYPEDEFS
56  **********************/
57 
58 typedef int32_t integer;
59 typedef bool boolean;
60 typedef lv_value_precise_t precise;
61 typedef lv_color_t color;
62 typedef const void * pointer;
63 
64 #define DEFINE_PROPERTY_SETTER_TYPES(type) \
65     typedef void (*lv_property_set_##type##_t)(lv_obj_t *, type); \
66     typedef void (*lv_property_set_##type##_integer_t)(lv_obj_t *, type, int32_t); \
67     typedef void (*lv_property_set_##type##_boolean_t)(lv_obj_t *, type, bool); \
68     typedef void (*lv_property_set_##type##_precise_t)(lv_obj_t *, type, lv_value_precise_t); \
69     typedef void (*lv_property_set_##type##_color_t)(lv_obj_t *, type, lv_color_t); \
70     typedef void (*lv_property_set_##type##_pointer_t)(lv_obj_t *, type, const void *)
71 
72 DEFINE_PROPERTY_SETTER_TYPES(integer);
73 DEFINE_PROPERTY_SETTER_TYPES(boolean);
74 DEFINE_PROPERTY_SETTER_TYPES(precise);
75 DEFINE_PROPERTY_SETTER_TYPES(color);
76 DEFINE_PROPERTY_SETTER_TYPES(pointer);
77 
78 typedef void (*lv_property_set_point_t)(lv_obj_t *, lv_point_t *);
79 typedef lv_result_t (*lv_property_setter_t)(lv_obj_t *, lv_prop_id_t, const lv_property_t *);
80 
81 typedef integer(*lv_property_get_integer_t)(const lv_obj_t *);
82 typedef bool (*lv_property_get_boolean_t)(const lv_obj_t *);
83 typedef lv_value_precise_t (*lv_property_get_precise_t)(const lv_obj_t *);
84 typedef lv_color_t (*lv_property_get_color_t)(const lv_obj_t *);
85 typedef void * (*lv_property_get_pointer_t)(const lv_obj_t *);
86 typedef lv_point_t (*lv_property_get_point_t)(lv_obj_t *);
87 
88 typedef lv_result_t (*lv_property_getter_t)(const lv_obj_t *, lv_prop_id_t, lv_property_t *);
89 
90 /**********************
91  *  STATIC PROTOTYPES
92  **********************/
93 
94 static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set);
95 static int property_name_compare(const void * ref, const void * element);
96 
97 /**********************
98  *  STATIC VARIABLES
99  **********************/
100 
101 /**********************
102  *      MACROS
103  **********************/
104 
105 /**********************
106  *   GLOBAL FUNCTIONS
107  **********************/
108 
lv_obj_set_property(lv_obj_t * obj,const lv_property_t * value)109 lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value)
110 {
111     LV_ASSERT(obj && value);
112 
113     uint32_t index = LV_PROPERTY_ID_INDEX(value->id);
114     if(value->id == LV_PROPERTY_ID_INVALID || index > LV_PROPERTY_ID_ANY) {
115         LV_LOG_WARN("Invalid property id set to %p", obj);
116         return LV_RESULT_INVALID;
117     }
118 
119     if(index < LV_PROPERTY_ID_START) {
120         lv_obj_set_local_style_prop(obj, index, value->style, value->selector);
121         return LV_RESULT_OK;
122     }
123 
124     return obj_property(obj, value->id, (lv_property_t *)value, true);
125 }
126 
lv_obj_set_properties(lv_obj_t * obj,const lv_property_t * value,uint32_t count)127 lv_result_t lv_obj_set_properties(lv_obj_t * obj, const lv_property_t * value, uint32_t count)
128 {
129     for(uint32_t i = 0; i < count; i++) {
130         lv_result_t result = lv_obj_set_property(obj, &value[i]);
131         if(result != LV_RESULT_OK) {
132             return result;
133         }
134     }
135 
136     return LV_RESULT_OK;
137 }
138 
lv_obj_get_property(lv_obj_t * obj,lv_prop_id_t id)139 lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id)
140 {
141     lv_result_t result;
142     lv_property_t value = { 0 };
143 
144     uint32_t index = LV_PROPERTY_ID_INDEX(id);
145     if(id == LV_PROPERTY_ID_INVALID || index > LV_PROPERTY_ID_ANY) {
146         LV_LOG_WARN("Invalid property id to get from %p", obj);
147         value.id = LV_PROPERTY_ID_INVALID;
148         value.num = 0;
149         return value;
150     }
151 
152     if(index < LV_PROPERTY_ID_START) {
153         lv_obj_get_local_style_prop(obj, index, &value.style, 0);
154         value.id = id;
155         value.selector = 0;
156         return value;
157     }
158 
159     result = obj_property(obj, id, &value, false);
160     if(result != LV_RESULT_OK)
161         value.id = LV_PROPERTY_ID_INVALID;
162 
163     return value;
164 }
165 
lv_obj_get_style_property(lv_obj_t * obj,lv_prop_id_t id,uint32_t selector)166 lv_property_t lv_obj_get_style_property(lv_obj_t * obj, lv_prop_id_t id, uint32_t selector)
167 {
168     lv_property_t value;
169     uint32_t index = LV_PROPERTY_ID_INDEX(id);
170 
171     if(index == LV_PROPERTY_ID_INVALID || index >= LV_PROPERTY_ID_START) {
172         LV_LOG_WARN("invalid style property id 0x%" LV_PRIx32, id);
173         value.id = LV_PROPERTY_ID_INVALID;
174         value.num = 0;
175         return value;
176     }
177 
178     lv_obj_get_local_style_prop(obj, id, &value.style, selector);
179     value.id = id;
180     value.selector = selector;
181     return value;
182 }
183 
lv_style_property_get_id(const char * name)184 lv_prop_id_t lv_style_property_get_id(const char * name)
185 {
186 #if LV_USE_OBJ_PROPERTY_NAME
187     lv_property_name_t * found;
188     /*Check style property*/
189     found = lv_utils_bsearch(name, lv_style_property_names, sizeof(lv_style_property_names) / sizeof(lv_property_name_t),
190                              sizeof(lv_property_name_t), property_name_compare);
191     if(found) return found->id;
192 #else
193     LV_UNUSED(name);
194 #endif
195     return LV_PROPERTY_ID_INVALID;
196 }
197 
lv_obj_class_property_get_id(const lv_obj_class_t * clz,const char * name)198 lv_prop_id_t lv_obj_class_property_get_id(const lv_obj_class_t * clz, const char * name)
199 {
200 #if LV_USE_OBJ_PROPERTY_NAME
201     const lv_property_name_t * names;
202     lv_property_name_t * found;
203 
204     names = clz->property_names;
205     if(names == NULL) {
206         /* try base class*/
207         return LV_PROPERTY_ID_INVALID;
208     }
209 
210     found = lv_utils_bsearch(name, names, clz->names_count, sizeof(lv_property_name_t), property_name_compare);
211     if(found) return found->id;
212 #else
213     LV_UNUSED(obj);
214     LV_UNUSED(name);
215     LV_UNUSED(property_name_compare);
216 #endif
217     return LV_PROPERTY_ID_INVALID;
218 }
219 
lv_obj_property_get_id(const lv_obj_t * obj,const char * name)220 lv_prop_id_t lv_obj_property_get_id(const lv_obj_t * obj, const char * name)
221 {
222 #if LV_USE_OBJ_PROPERTY_NAME
223     const lv_obj_class_t * clz;
224     lv_prop_id_t id;
225 
226     for(clz = obj->class_p; clz; clz = clz->base_class) {
227         id = lv_obj_class_property_get_id(clz, name);
228         if(id != LV_PROPERTY_ID_INVALID) return id;
229     }
230 
231     /*Check style property*/
232     id = lv_style_property_get_id(name);
233     if(id != LV_PROPERTY_ID_INVALID) return id;
234 #else
235     LV_UNUSED(obj);
236     LV_UNUSED(name);
237     LV_UNUSED(property_name_compare);
238 #endif
239     return LV_PROPERTY_ID_INVALID;
240 }
241 
242 /**********************
243  *  STATIC FUNCTIONS
244  **********************/
245 
obj_property(lv_obj_t * obj,lv_prop_id_t id,lv_property_t * value,bool set)246 static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set)
247 {
248     const lv_property_ops_t * properties;
249     const lv_property_ops_t * prop;
250 
251     const lv_obj_class_t * clz;
252     uint32_t index = LV_PROPERTY_ID_INDEX(id);
253 
254     for(clz = obj->class_p ; clz; clz = clz->base_class) {
255         properties = clz->properties;
256         if(properties == NULL) {
257             /* try base class*/
258             continue;
259         }
260 
261         if(id != LV_PROPERTY_ID_ANY && (index < clz->prop_index_start || index > clz->prop_index_end)) {
262             /* try base class*/
263             continue;
264         }
265 
266         /*Check if there's setter available for this class*/
267         for(uint32_t i = 0; i < clz->properties_count; i++) {
268             prop = &properties[i];
269 
270             /*pass id and value directly to widget's property method*/
271             if(prop->id == LV_PROPERTY_ID_ANY) {
272                 value->id = prop->id;
273                 if(set) return ((lv_property_setter_t)prop->setter)(obj, id, value);
274                 else return ((lv_property_getter_t)prop->getter)(obj, id, value);
275             }
276 
277             /*Not this id, check next*/
278             if(prop->id != id)
279                 continue;
280 
281             /*id matched but we got null pointer to functions*/
282             if(set ? prop->setter == NULL : prop->getter == NULL) {
283                 LV_LOG_WARN("NULL %s provided, id: 0x%" LV_PRIx32, set ? "setter" : "getter", id);
284                 return LV_RESULT_INVALID;
285             }
286 
287             /*Update value id if it's a read*/
288             if(!set) value->id = prop->id;
289 
290             switch(LV_PROPERTY_ID_TYPE(prop->id)) {
291                 case LV_PROPERTY_TYPE_INT:
292                     HANDLE_PROPERTY_TYPE(integer, num);
293                     break;
294                 case LV_PROPERTY_TYPE_BOOL:
295                     HANDLE_PROPERTY_TYPE(boolean, enable);
296                     break;
297                 case LV_PROPERTY_TYPE_PRECISE:
298                     HANDLE_PROPERTY_TYPE(precise, precise);
299                     break;
300                 case LV_PROPERTY_TYPE_COLOR:
301                     HANDLE_PROPERTY_TYPE(color, color);
302                     break;
303                 case LV_PROPERTY_TYPE_POINTER:
304                 case LV_PROPERTY_TYPE_IMGSRC:
305                 case LV_PROPERTY_TYPE_TEXT:
306                 case LV_PROPERTY_TYPE_OBJ:
307                 case LV_PROPERTY_TYPE_DISPLAY:
308                 case LV_PROPERTY_TYPE_FONT:
309                     HANDLE_PROPERTY_TYPE(pointer, ptr);
310                     break;
311                 case LV_PROPERTY_TYPE_POINT: {
312                         lv_point_t * point = &value->point;
313                         if(set)((lv_property_set_point_t)(prop->setter))(obj, point);
314                         else *point = ((lv_property_get_point_t)(prop->getter))(obj);
315                         break;
316                     }
317                 default: {
318                         LV_LOG_WARN("Unknown property id: 0x%08" LV_PRIx32, prop->id);
319                         return LV_RESULT_INVALID;
320                     }
321             }
322 
323             return LV_RESULT_OK;
324         }
325 
326         /*If no setter found, try base class then*/
327     }
328 
329     LV_LOG_WARN("Unknown property id: 0x%08" LV_PRIx32, id);
330     return LV_RESULT_INVALID;
331 }
332 
property_name_compare(const void * ref,const void * element)333 static int property_name_compare(const void * ref, const void * element)
334 {
335     const lv_property_name_t * prop = element;
336     return lv_strcmp(ref, prop->name);
337 }
338 
339 #endif /*LV_USE_OBJ_PROPERTY*/
340