1 /**
2  * @file lv_observer.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_observer_private.h"
11 #if LV_USE_OBSERVER
12 
13 #include "../../lvgl.h"
14 #include "../../core/lv_obj_private.h"
15 #include "../../misc/lv_event_private.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 typedef struct {
25     uint32_t flag;
26     lv_subject_value_t value;
27     uint32_t inv    : 1;
28 } flag_and_cond_t;
29 
30 /**********************
31  *  STATIC PROTOTYPES
32  **********************/
33 static void unsubscribe_on_delete_cb(lv_event_t * e);
34 static void group_notify_cb(lv_observer_t * observer, lv_subject_t * subject);
35 static lv_observer_t * bind_to_bitfield(lv_subject_t * subject, lv_obj_t * obj, lv_observer_cb_t cb, uint32_t flag,
36                                         int32_t ref_value, bool inv);
37 static void obj_flag_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
38 static void obj_state_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
39 static void obj_value_changed_event_cb(lv_event_t * e);
40 
41 #if LV_USE_LABEL
42     static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
43 #endif
44 
45 #if LV_USE_ARC
46     static void arc_value_changed_event_cb(lv_event_t * e);
47     static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
48 #endif
49 
50 #if LV_USE_SLIDER
51     static void slider_value_changed_event_cb(lv_event_t * e);
52     static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
53 #endif
54 
55 #if LV_USE_ROLLER
56     static void roller_value_changed_event_cb(lv_event_t * e);
57     static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
58 #endif
59 
60 #if LV_USE_DROPDOWN
61     static void dropdown_value_changed_event_cb(lv_event_t * e);
62     static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
63 #endif
64 
65 /**********************
66  *  STATIC VARIABLES
67  **********************/
68 
69 /**********************
70  *      MACROS
71  **********************/
72 
73 /**********************
74  *   GLOBAL FUNCTIONS
75  **********************/
76 
lv_subject_init_int(lv_subject_t * subject,int32_t value)77 void lv_subject_init_int(lv_subject_t * subject, int32_t value)
78 {
79     lv_memzero(subject, sizeof(lv_subject_t));
80     subject->type = LV_SUBJECT_TYPE_INT;
81     subject->value.num = value;
82     subject->prev_value.num = value;
83     lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
84 }
85 
lv_subject_set_int(lv_subject_t * subject,int32_t value)86 void lv_subject_set_int(lv_subject_t * subject, int32_t value)
87 {
88     if(subject->type != LV_SUBJECT_TYPE_INT) {
89         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_INT");
90         return;
91     }
92 
93     subject->prev_value.num = subject->value.num;
94     subject->value.num = value;
95     lv_subject_notify(subject);
96 }
97 
lv_subject_get_int(lv_subject_t * subject)98 int32_t lv_subject_get_int(lv_subject_t * subject)
99 {
100     if(subject->type != LV_SUBJECT_TYPE_INT) {
101         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_INT");
102         return 0;
103     }
104 
105     return subject->value.num;
106 }
107 
lv_subject_get_previous_int(lv_subject_t * subject)108 int32_t lv_subject_get_previous_int(lv_subject_t * subject)
109 {
110     if(subject->type != LV_SUBJECT_TYPE_INT) {
111         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_INT");
112         return 0;
113     }
114 
115     return subject->prev_value.num;
116 }
117 
lv_subject_init_string(lv_subject_t * subject,char * buf,char * prev_buf,size_t size,const char * value)118 void lv_subject_init_string(lv_subject_t * subject, char * buf, char * prev_buf, size_t size, const char * value)
119 {
120     lv_memzero(subject, sizeof(lv_subject_t));
121     lv_strlcpy(buf, value, size);
122     if(prev_buf) lv_strlcpy(prev_buf, value, size);
123 
124     subject->type = LV_SUBJECT_TYPE_STRING;
125     subject->size = size;
126     subject->value.pointer = buf;
127     subject->prev_value.pointer = prev_buf;
128 
129     lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
130 }
131 
lv_subject_copy_string(lv_subject_t * subject,const char * buf)132 void lv_subject_copy_string(lv_subject_t * subject, const char * buf)
133 {
134     if(subject->type != LV_SUBJECT_TYPE_STRING) {
135         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_STRING");
136         return;
137     }
138 
139     if(subject->size < 1) return;
140     if(subject->prev_value.pointer) {
141         lv_strlcpy((char *)subject->prev_value.pointer, subject->value.pointer, subject->size);
142     }
143 
144     lv_strlcpy((char *)subject->value.pointer, buf, subject->size);
145 
146     lv_subject_notify(subject);
147 
148 }
149 
lv_subject_snprintf(lv_subject_t * subject,const char * format,...)150 void lv_subject_snprintf(lv_subject_t * subject, const char * format, ...)
151 {
152     if(subject->type != LV_SUBJECT_TYPE_STRING) {
153         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_STRING");
154         return;
155     }
156 
157     if(subject->size < 1) return;
158 
159     if(subject->prev_value.pointer) {
160         lv_strlcpy((char *)subject->prev_value.pointer, subject->value.pointer, subject->size);
161     }
162 
163     va_list va;
164     va_start(va, format);
165     const int ret = lv_vsnprintf((char *)subject->value.pointer, subject->size, format, va);
166     LV_UNUSED(ret);
167     va_end(va);
168 
169     lv_subject_notify(subject);
170 }
171 
lv_subject_get_string(lv_subject_t * subject)172 const char * lv_subject_get_string(lv_subject_t * subject)
173 {
174     if(subject->type != LV_SUBJECT_TYPE_STRING) {
175         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_STRING");
176         return "";
177     }
178 
179     return subject->value.pointer;
180 }
181 
lv_subject_get_previous_string(lv_subject_t * subject)182 const char * lv_subject_get_previous_string(lv_subject_t * subject)
183 {
184     if(subject->type != LV_SUBJECT_TYPE_STRING) {
185         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_STRING");
186         return NULL;
187     }
188 
189     return subject->prev_value.pointer;
190 }
191 
lv_subject_init_pointer(lv_subject_t * subject,void * value)192 void lv_subject_init_pointer(lv_subject_t * subject, void * value)
193 {
194     lv_memzero(subject, sizeof(lv_subject_t));
195     subject->type = LV_SUBJECT_TYPE_POINTER;
196     subject->value.pointer = value;
197     subject->prev_value.pointer = value;
198     lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
199 }
200 
lv_subject_set_pointer(lv_subject_t * subject,void * ptr)201 void lv_subject_set_pointer(lv_subject_t * subject, void * ptr)
202 {
203     if(subject->type != LV_SUBJECT_TYPE_POINTER) {
204         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_POINTER");
205         return;
206     }
207 
208     subject->prev_value.pointer = subject->value.pointer;
209     subject->value.pointer = ptr;
210     lv_subject_notify(subject);
211 }
212 
lv_subject_get_pointer(lv_subject_t * subject)213 const void * lv_subject_get_pointer(lv_subject_t * subject)
214 {
215     if(subject->type != LV_SUBJECT_TYPE_POINTER) {
216         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_POINTER");
217         return NULL;
218     }
219 
220     return subject->value.pointer;
221 }
222 
lv_subject_get_previous_pointer(lv_subject_t * subject)223 const void * lv_subject_get_previous_pointer(lv_subject_t * subject)
224 {
225     if(subject->type != LV_SUBJECT_TYPE_POINTER) {
226         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_POINTER");
227         return NULL;
228     }
229 
230     return subject->prev_value.pointer;
231 }
232 
lv_subject_init_color(lv_subject_t * subject,lv_color_t color)233 void lv_subject_init_color(lv_subject_t * subject, lv_color_t color)
234 {
235     lv_memzero(subject, sizeof(lv_subject_t));
236     subject->type = LV_SUBJECT_TYPE_COLOR;
237     subject->value.color = color;
238     subject->prev_value.color = color;
239     lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
240 }
241 
lv_subject_set_color(lv_subject_t * subject,lv_color_t color)242 void lv_subject_set_color(lv_subject_t * subject, lv_color_t color)
243 {
244     if(subject->type != LV_SUBJECT_TYPE_COLOR) {
245         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_COLOR");
246         return;
247     }
248 
249     subject->prev_value.color = subject->value.color;
250     subject->value.color = color;
251     lv_subject_notify(subject);
252 }
253 
lv_subject_get_color(lv_subject_t * subject)254 lv_color_t lv_subject_get_color(lv_subject_t * subject)
255 {
256     if(subject->type != LV_SUBJECT_TYPE_COLOR) {
257         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_COLOR");
258         return lv_color_black();
259     }
260 
261     return subject->value.color;
262 }
263 
lv_subject_get_previous_color(lv_subject_t * subject)264 lv_color_t lv_subject_get_previous_color(lv_subject_t * subject)
265 {
266     if(subject->type != LV_SUBJECT_TYPE_COLOR) {
267         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_COLOR");
268         return lv_color_black();
269     }
270 
271     return subject->prev_value.color;
272 }
273 
lv_subject_init_group(lv_subject_t * subject,lv_subject_t * list[],uint32_t list_len)274 void lv_subject_init_group(lv_subject_t * subject, lv_subject_t * list[], uint32_t list_len)
275 {
276     subject->type = LV_SUBJECT_TYPE_GROUP;
277     subject->size = list_len;
278     lv_ll_init(&(subject->subs_ll), sizeof(lv_observer_t));
279     subject->value.pointer = list;
280 
281     /* bind all subjects to this subject */
282     uint32_t i;
283     for(i = 0; i < list_len; i++) {
284         /*If a subject in the group changes notify the group itself*/
285         lv_subject_add_observer(list[i], group_notify_cb, subject);
286     }
287 }
288 
lv_subject_deinit(lv_subject_t * subject)289 void lv_subject_deinit(lv_subject_t * subject)
290 {
291     lv_observer_t * observer = lv_ll_get_head(&subject->subs_ll);
292     while(observer) {
293         lv_observer_t * observer_next = lv_ll_get_next(&subject->subs_ll, observer);
294 
295         if(observer->for_obj) {
296             lv_obj_remove_event_cb(observer->target, unsubscribe_on_delete_cb);
297             lv_obj_remove_event_cb_with_user_data(observer->target, NULL, subject);
298         }
299 
300         lv_observer_remove(observer);
301         observer = observer_next;
302     }
303 
304     lv_ll_clear(&subject->subs_ll);
305 }
306 
lv_subject_get_group_element(lv_subject_t * subject,int32_t index)307 lv_subject_t * lv_subject_get_group_element(lv_subject_t * subject, int32_t index)
308 {
309     if(subject->type != LV_SUBJECT_TYPE_GROUP) {
310         LV_LOG_WARN("Subject type is not LV_SUBJECT_TYPE_GROUP");
311         return NULL;
312     }
313 
314     if(index >= subject->size)  return NULL;
315 
316     return ((lv_subject_t **)(subject->value.pointer))[index];
317 }
318 
lv_subject_add_observer(lv_subject_t * subject,lv_observer_cb_t cb,void * user_data)319 lv_observer_t * lv_subject_add_observer(lv_subject_t * subject, lv_observer_cb_t cb, void * user_data)
320 {
321     lv_observer_t * observer = lv_subject_add_observer_obj(subject, cb, NULL, user_data);
322     if(observer == NULL) return NULL;
323 
324     observer->for_obj = 0;
325     return observer;
326 }
327 
lv_subject_add_observer_obj(lv_subject_t * subject,lv_observer_cb_t cb,lv_obj_t * obj,void * user_data)328 lv_observer_t * lv_subject_add_observer_obj(lv_subject_t * subject, lv_observer_cb_t cb, lv_obj_t * obj,
329                                             void * user_data)
330 {
331     LV_ASSERT_NULL(subject);
332     if(subject->type == LV_SUBJECT_TYPE_INVALID) {
333         LV_LOG_WARN("Subject not initialized yet");
334         return NULL;
335     }
336     lv_observer_t * observer = lv_ll_ins_tail(&(subject->subs_ll));
337     LV_ASSERT_MALLOC(observer);
338     if(observer == NULL) return NULL;
339 
340     lv_memzero(observer, sizeof(*observer));
341 
342     observer->subject = subject;
343     observer->cb = cb;
344     observer->user_data = user_data;
345     observer->target = obj;
346     observer->for_obj = 1;
347     /* subscribe to delete event of the object */
348     if(obj != NULL) {
349         lv_obj_add_event_cb(obj, unsubscribe_on_delete_cb, LV_EVENT_DELETE, observer);
350     }
351 
352     /* update object immediately */
353     if(observer->cb) observer->cb(observer, subject);
354 
355     return observer;
356 }
357 
lv_subject_add_observer_with_target(lv_subject_t * subject,lv_observer_cb_t cb,void * target,void * user_data)358 lv_observer_t * lv_subject_add_observer_with_target(lv_subject_t * subject, lv_observer_cb_t cb, void * target,
359                                                     void * user_data)
360 {
361     LV_ASSERT_NULL(subject);
362     if(subject->type == LV_SUBJECT_TYPE_INVALID) {
363         LV_LOG_WARN("Subject not initialized yet");
364         return NULL;
365     }
366     lv_observer_t * observer = lv_ll_ins_tail(&(subject->subs_ll));
367     LV_ASSERT_MALLOC(observer);
368     if(observer == NULL) return NULL;
369 
370     lv_memzero(observer, sizeof(*observer));
371 
372     observer->subject = subject;
373     observer->cb = cb;
374     observer->user_data = user_data;
375     observer->target = target;
376 
377     /* update object immediately */
378     if(observer->cb) observer->cb(observer, subject);
379 
380     return observer;
381 }
382 
383 
lv_observer_remove(lv_observer_t * observer)384 void lv_observer_remove(lv_observer_t * observer)
385 {
386     LV_ASSERT_NULL(observer);
387 
388     observer->subject->notify_restart_query = 1;
389 
390     lv_ll_remove(&(observer->subject->subs_ll), observer);
391 
392     if(observer->auto_free_user_data) {
393         lv_free(observer->user_data);
394     }
395     lv_free(observer);
396 }
397 
lv_obj_remove_from_subject(lv_obj_t * obj,lv_subject_t * subject)398 void lv_obj_remove_from_subject(lv_obj_t * obj, lv_subject_t * subject)
399 {
400     int32_t i;
401     int32_t event_cnt = (int32_t)(obj->spec_attr ? lv_event_get_count(&obj->spec_attr->event_list) : 0);
402     for(i = event_cnt - 1; i >= 0; i--) {
403         lv_event_dsc_t * event_dsc = lv_obj_get_event_dsc(obj, i);
404         if(event_dsc->cb == unsubscribe_on_delete_cb) {
405             lv_observer_t * observer = event_dsc->user_data;
406             if(subject == NULL || subject == observer->subject) {
407                 lv_observer_remove(observer);
408                 lv_obj_remove_event(obj, i);
409             }
410         }
411     }
412 }
413 
lv_observer_get_target(lv_observer_t * observer)414 void * lv_observer_get_target(lv_observer_t * observer)
415 {
416     LV_ASSERT_NULL(observer);
417 
418     return observer->target;
419 }
420 
lv_subject_notify(lv_subject_t * subject)421 void lv_subject_notify(lv_subject_t * subject)
422 {
423     LV_ASSERT_NULL(subject);
424 
425     lv_observer_t * observer;
426     LV_LL_READ(&(subject->subs_ll), observer) {
427         observer->notified = 0;
428     }
429 
430     do {
431         subject->notify_restart_query = 0;
432         LV_LL_READ(&(subject->subs_ll), observer) {
433             if(observer->cb && observer->notified == 0) {
434                 observer->cb(observer, subject);
435                 if(subject->notify_restart_query) break;
436                 observer->notified = 1;
437             }
438         }
439     } while(subject->notify_restart_query);
440 }
441 
lv_obj_bind_flag_if_eq(lv_obj_t * obj,lv_subject_t * subject,lv_obj_flag_t flag,int32_t ref_value)442 lv_observer_t * lv_obj_bind_flag_if_eq(lv_obj_t * obj, lv_subject_t * subject, lv_obj_flag_t flag, int32_t ref_value)
443 {
444     lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_flag_observer_cb, flag, ref_value, false);
445     return observable;
446 }
447 
lv_obj_bind_flag_if_not_eq(lv_obj_t * obj,lv_subject_t * subject,lv_obj_flag_t flag,int32_t ref_value)448 lv_observer_t * lv_obj_bind_flag_if_not_eq(lv_obj_t * obj, lv_subject_t * subject, lv_obj_flag_t flag,
449                                            int32_t ref_value)
450 {
451     lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_flag_observer_cb, flag, ref_value, true);
452     return observable;
453 }
454 
lv_obj_bind_state_if_eq(lv_obj_t * obj,lv_subject_t * subject,lv_state_t state,int32_t ref_value)455 lv_observer_t * lv_obj_bind_state_if_eq(lv_obj_t * obj, lv_subject_t * subject, lv_state_t state, int32_t ref_value)
456 {
457     lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_state_observer_cb, state, ref_value, false);
458     return observable;
459 }
460 
lv_obj_bind_state_if_not_eq(lv_obj_t * obj,lv_subject_t * subject,lv_state_t state,int32_t ref_value)461 lv_observer_t * lv_obj_bind_state_if_not_eq(lv_obj_t * obj, lv_subject_t * subject, lv_state_t state, int32_t ref_value)
462 {
463     lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_state_observer_cb, state, ref_value, true);
464     return observable;
465 }
466 
lv_obj_bind_checked(lv_obj_t * obj,lv_subject_t * subject)467 lv_observer_t * lv_obj_bind_checked(lv_obj_t * obj, lv_subject_t * subject)
468 {
469     lv_observer_t * observable = bind_to_bitfield(subject, obj, obj_state_observer_cb, LV_STATE_CHECKED, 1, false);
470     lv_obj_add_event_cb(obj, obj_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject);
471     return observable;
472 }
473 
474 #if LV_USE_LABEL
lv_label_bind_text(lv_obj_t * obj,lv_subject_t * subject,const char * fmt)475 lv_observer_t * lv_label_bind_text(lv_obj_t * obj, lv_subject_t * subject, const char * fmt)
476 {
477     LV_ASSERT_NULL(subject);
478     LV_ASSERT_NULL(obj);
479 
480     if(fmt == NULL) {
481         if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER) {
482             LV_LOG_WARN("Incompatible subject type: %d", subject->type);
483             return NULL;
484         }
485     }
486     else {
487         if(subject->type != LV_SUBJECT_TYPE_STRING && subject->type != LV_SUBJECT_TYPE_POINTER &&
488            subject->type != LV_SUBJECT_TYPE_INT) {
489             LV_LOG_WARN("Incompatible subject type: %d", subject->type);
490             return NULL;
491         }
492     }
493 
494     lv_observer_t * observer = lv_subject_add_observer_obj(subject, label_text_observer_cb, obj, (void *)fmt);
495     return observer;
496 }
497 #endif /*LV_USE_LABEL*/
498 
499 #if LV_USE_ARC
lv_arc_bind_value(lv_obj_t * obj,lv_subject_t * subject)500 lv_observer_t * lv_arc_bind_value(lv_obj_t * obj, lv_subject_t * subject)
501 {
502     LV_ASSERT_NULL(subject);
503     LV_ASSERT_NULL(obj);
504 
505     if(subject->type != LV_SUBJECT_TYPE_INT) {
506         LV_LOG_WARN("Incompatible subject type: %d", subject->type);
507         return NULL;
508     }
509 
510     lv_obj_add_event_cb(obj, arc_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject);
511 
512     lv_observer_t * observer = lv_subject_add_observer_obj(subject, arc_value_observer_cb, obj, NULL);
513     return observer;
514 }
515 #endif /*LV_USE_ARC*/
516 
517 #if LV_USE_SLIDER
lv_slider_bind_value(lv_obj_t * obj,lv_subject_t * subject)518 lv_observer_t * lv_slider_bind_value(lv_obj_t * obj, lv_subject_t * subject)
519 {
520     LV_ASSERT_NULL(subject);
521     LV_ASSERT_NULL(obj);
522 
523     if(subject->type != LV_SUBJECT_TYPE_INT) {
524         LV_LOG_WARN("Incompatible subject type: %d", subject->type);
525         return NULL;
526     }
527 
528     lv_obj_add_event_cb(obj, slider_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject);
529 
530     lv_observer_t * observer = lv_subject_add_observer_obj(subject, slider_value_observer_cb, obj, NULL);
531     return observer;
532 }
533 #endif /*LV_USE_SLIDER*/
534 
535 #if LV_USE_ROLLER
536 
lv_roller_bind_value(lv_obj_t * obj,lv_subject_t * subject)537 lv_observer_t * lv_roller_bind_value(lv_obj_t * obj, lv_subject_t * subject)
538 {
539     LV_ASSERT_NULL(subject);
540     LV_ASSERT_NULL(obj);
541 
542     if(subject->type != LV_SUBJECT_TYPE_INT) {
543         LV_LOG_WARN("Incompatible subject type: %d", subject->type);
544         return NULL;
545     }
546 
547     lv_obj_add_event_cb(obj, roller_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject);
548 
549     lv_observer_t * observer = lv_subject_add_observer_obj(subject, roller_value_observer_cb, obj, NULL);
550     return observer;
551 
552 }
553 #endif /*LV_USE_ROLLER*/
554 
555 #if LV_USE_DROPDOWN
556 
lv_dropdown_bind_value(lv_obj_t * obj,lv_subject_t * subject)557 lv_observer_t * lv_dropdown_bind_value(lv_obj_t * obj, lv_subject_t * subject)
558 {
559     LV_ASSERT_NULL(subject);
560     LV_ASSERT_NULL(obj);
561 
562     if(subject->type != LV_SUBJECT_TYPE_INT) {
563         LV_LOG_WARN("Incompatible subject type: %d", subject->type);
564         return NULL;
565     }
566 
567     lv_obj_add_event_cb(obj, dropdown_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, subject);
568 
569     lv_observer_t * observer = lv_subject_add_observer_obj(subject, dropdown_value_observer_cb, obj, NULL);
570     return observer;
571 
572 }
573 
574 #endif /*LV_USE_DROPDOWN*/
575 
lv_observer_get_target_obj(lv_observer_t * observer)576 lv_obj_t * lv_observer_get_target_obj(lv_observer_t * observer)
577 {
578     return (lv_obj_t *)lv_observer_get_target(observer);
579 }
580 
lv_observer_get_user_data(const lv_observer_t * observer)581 void * lv_observer_get_user_data(const lv_observer_t * observer)
582 {
583     LV_ASSERT_NULL(observer);
584 
585     return observer->user_data;
586 }
587 
588 /**********************
589  *   STATIC FUNCTIONS
590  **********************/
591 
group_notify_cb(lv_observer_t * observer,lv_subject_t * subject)592 static void group_notify_cb(lv_observer_t * observer, lv_subject_t * subject)
593 {
594     LV_UNUSED(subject);
595     lv_subject_t * subject_group = observer->user_data;
596     lv_subject_notify(subject_group);
597 }
598 
unsubscribe_on_delete_cb(lv_event_t * e)599 static void unsubscribe_on_delete_cb(lv_event_t * e)
600 {
601     lv_observer_t * observer = lv_event_get_user_data(e);
602     lv_observer_remove(observer);
603 }
604 
bind_to_bitfield(lv_subject_t * subject,lv_obj_t * obj,lv_observer_cb_t cb,uint32_t flag,int32_t ref_value,bool inv)605 static lv_observer_t * bind_to_bitfield(lv_subject_t * subject, lv_obj_t * obj, lv_observer_cb_t cb, uint32_t flag,
606                                         int32_t ref_value, bool inv)
607 {
608     LV_ASSERT_NULL(subject);
609     LV_ASSERT_NULL(obj);
610 
611     if(subject->type != LV_SUBJECT_TYPE_INT) {
612         LV_LOG_WARN("Incompatible subject type: %d", subject->type);
613         return NULL;
614     }
615 
616     flag_and_cond_t * p = lv_malloc(sizeof(flag_and_cond_t));
617     if(p == NULL) {
618         LV_LOG_WARN("Out of memory");
619         return NULL;
620     }
621 
622     p->flag = flag;
623     p->value.num = ref_value;
624     p->inv = inv;
625 
626     lv_observer_t * observable = lv_subject_add_observer_obj(subject, cb, obj, p);
627     observable->auto_free_user_data = 1;
628     return observable;
629 }
630 
obj_flag_observer_cb(lv_observer_t * observer,lv_subject_t * subject)631 static void obj_flag_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
632 {
633     flag_and_cond_t * p = observer->user_data;
634 
635     bool res = subject->value.num == p->value.num;
636     if(p->inv) res = !res;
637 
638     if(res) {
639         lv_obj_add_flag(observer->target, p->flag);
640     }
641     else {
642         lv_obj_remove_flag(observer->target, p->flag);
643     }
644 }
645 
obj_state_observer_cb(lv_observer_t * observer,lv_subject_t * subject)646 static void obj_state_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
647 {
648     flag_and_cond_t * p = observer->user_data;
649 
650     bool res = subject->value.num == p->value.num;
651     if(p->inv) res = !res;
652 
653     if(res) {
654         lv_obj_add_state(observer->target, p->flag);
655     }
656     else {
657         lv_obj_remove_state(observer->target, p->flag);
658     }
659 }
660 
obj_value_changed_event_cb(lv_event_t * e)661 static void obj_value_changed_event_cb(lv_event_t * e)
662 {
663     lv_obj_t * obj = lv_event_get_current_target(e);
664     lv_subject_t * subject = lv_event_get_user_data(e);
665 
666     lv_subject_set_int(subject, lv_obj_has_state(obj, LV_STATE_CHECKED));
667 }
668 
669 #if LV_USE_LABEL
670 
label_text_observer_cb(lv_observer_t * observer,lv_subject_t * subject)671 static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
672 {
673     const char * fmt = observer->user_data;
674 
675     if(fmt == NULL) {
676         lv_label_set_text(observer->target, subject->value.pointer);
677     }
678     else {
679         switch(subject->type) {
680             case LV_SUBJECT_TYPE_INT:
681                 lv_label_set_text_fmt(observer->target, fmt, subject->value.num);
682                 break;
683             case LV_SUBJECT_TYPE_STRING:
684             case LV_SUBJECT_TYPE_POINTER:
685                 lv_label_set_text_fmt(observer->target, fmt, subject->value.pointer);
686                 break;
687             default:
688                 break;
689         }
690     }
691 }
692 
693 #endif /*LV_USE_LABEL*/
694 
695 #if LV_USE_ARC
696 
arc_value_changed_event_cb(lv_event_t * e)697 static void arc_value_changed_event_cb(lv_event_t * e)
698 {
699     lv_obj_t * arc = lv_event_get_current_target(e);
700     lv_subject_t * subject = lv_event_get_user_data(e);
701 
702     lv_subject_set_int(subject, lv_arc_get_value(arc));
703 }
704 
arc_value_observer_cb(lv_observer_t * observer,lv_subject_t * subject)705 static void arc_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
706 {
707     lv_arc_set_value(observer->target, subject->value.num);
708 }
709 
710 #endif /*LV_USE_ARC*/
711 
712 #if LV_USE_SLIDER
713 
slider_value_changed_event_cb(lv_event_t * e)714 static void slider_value_changed_event_cb(lv_event_t * e)
715 {
716     lv_obj_t * slider = lv_event_get_current_target(e);
717     lv_subject_t * subject = lv_event_get_user_data(e);
718 
719     lv_subject_set_int(subject, lv_slider_get_value(slider));
720 }
721 
slider_value_observer_cb(lv_observer_t * observer,lv_subject_t * subject)722 static void slider_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
723 {
724     lv_slider_set_value(observer->target, subject->value.num, LV_ANIM_OFF);
725 }
726 
727 #endif /*LV_USE_SLIDER*/
728 
729 #if LV_USE_ROLLER
730 
roller_value_changed_event_cb(lv_event_t * e)731 static void roller_value_changed_event_cb(lv_event_t * e)
732 {
733     lv_obj_t * roller = lv_event_get_current_target(e);
734     lv_subject_t * subject = lv_event_get_user_data(e);
735 
736     lv_subject_set_int(subject, lv_roller_get_selected(roller));
737 }
738 
roller_value_observer_cb(lv_observer_t * observer,lv_subject_t * subject)739 static void roller_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
740 {
741     if((int32_t)lv_roller_get_selected(observer->target) != subject->value.num) {
742         lv_roller_set_selected(observer->target, subject->value.num, LV_ANIM_OFF);
743     }
744 }
745 
746 #endif /*LV_USE_ROLLER*/
747 
748 #if LV_USE_DROPDOWN
749 
dropdown_value_changed_event_cb(lv_event_t * e)750 static void dropdown_value_changed_event_cb(lv_event_t * e)
751 {
752     lv_obj_t * dropdown = lv_event_get_current_target(e);
753     lv_subject_t * subject = lv_event_get_user_data(e);
754 
755     lv_subject_set_int(subject, lv_dropdown_get_selected(dropdown));
756 }
757 
dropdown_value_observer_cb(lv_observer_t * observer,lv_subject_t * subject)758 static void dropdown_value_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
759 {
760     lv_dropdown_set_selected(observer->target, subject->value.num, LV_ANIM_OFF);
761 }
762 
763 #endif /*LV_USE_DROPDOWN*/
764 
765 #endif /*LV_USE_OBSERVER*/
766