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