1 /**
2  * @file lv_demo_high_res_top_margin.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_demo_high_res_private.h"
11 #if LV_USE_DEMO_HIGH_RES
12 
13 #include "../../src/widgets/image/lv_image.h"
14 #include "../../src/widgets/label/lv_label.h"
15 #include "../../src/widgets/line/lv_line.h"
16 #include "../../src/display/lv_display_private.h"
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 
30 static void logout_cb(lv_event_t * e);
31 static lv_obj_t * create_icon(lv_obj_t * parent, lv_subject_t * subject, lv_image_dsc_t ** img_dsc_pair,
32                               lv_demo_high_res_ctx_t * c);
33 static void delete_modal_cb(lv_event_t * e);
34 static void icon_clicked_cb(lv_event_t * e);
35 static void sys_layer_clicked_cb(lv_event_t * e);
36 static void wifi_ssid_ip_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
37 static lv_obj_t * create_wifi(lv_obj_t * parent, lv_demo_high_res_ctx_t * c);
38 static void wifi_icon_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
39 static lv_obj_t * create_perfmon(lv_obj_t * parent, lv_demo_high_res_ctx_t * c);
40 #if LV_USE_PERF_MONITOR
41     static void perfmon_data_cb(lv_observer_t * observer, lv_subject_t * subject);
42 #endif
43 static lv_obj_t * create_settings(lv_obj_t * parent, lv_demo_high_res_ctx_t * c);
44 static lv_obj_t * create_setting_label_cont(lv_obj_t * parent, const char * text, lv_demo_high_res_ctx_t * c);
45 static void setting_clicked_cb(lv_event_t * e);
46 static void date_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
47 static void time_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
48 
49 /**********************
50  *  STATIC VARIABLES
51  **********************/
52 
53 /**********************
54  *      MACROS
55  **********************/
56 
57 #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(*arr))
58 
59 /**********************
60  *   GLOBAL FUNCTIONS
61  **********************/
62 
lv_demo_high_res_top_margin_create(lv_obj_t * parent,int32_t pad_hor,bool show_time,lv_demo_high_res_ctx_t * c)63 lv_obj_t * lv_demo_high_res_top_margin_create(lv_obj_t * parent, int32_t pad_hor, bool show_time,
64                                               lv_demo_high_res_ctx_t * c)
65 {
66     if(!c->top_margin_subjects_are_init) {
67         c->top_margin_subjects_are_init = true;
68         lv_subject_init_int(&c->top_margin_wifi_subject, 0);
69         lv_subject_init_int(&c->top_margin_health_subject, 0);
70         lv_subject_init_int(&c->top_margin_setting_subject, 0);
71     }
72 
73     lv_obj_t * top_margin = lv_obj_create(parent);
74     lv_obj_remove_style_all(top_margin);
75     lv_obj_set_size(top_margin, LV_PCT(100), c->sz->gap[10]);
76     lv_obj_set_style_pad_hor(top_margin, pad_hor, 0);
77     lv_obj_set_flex_flow(top_margin, LV_FLEX_FLOW_ROW);
78     lv_obj_set_flex_align(top_margin, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
79 
80     if(show_time) {
81         lv_obj_t * date_label = lv_label_create(top_margin);
82         lv_obj_add_style(date_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
83         lv_obj_add_style(date_label, &c->fonts[FONT_LABEL_SM], 0);
84         lv_subject_add_observer_obj(&c->subject_groups.date.group, date_observer_cb, date_label, c);
85 
86         lv_obj_t * time_label = lv_label_create(top_margin);
87         lv_obj_add_style(time_label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
88         lv_obj_add_style(time_label, &c->fonts[FONT_LABEL_SM], 0);
89         lv_subject_add_observer_obj(&c->subject_groups.time.group, time_observer_cb, time_label, c);
90     }
91     else {
92         lv_obj_t * logout_icon = lv_image_create(top_margin);
93         lv_image_set_src(logout_icon, c->imgs[IMG_LOGOUT_ICON]);
94         lv_obj_add_style(logout_icon, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_A8_IMG], 0);
95         lv_obj_add_flag(logout_icon, LV_OBJ_FLAG_CLICKABLE);
96         lv_obj_add_event_cb(logout_icon, logout_cb, LV_EVENT_CLICKED, c);
97     }
98 
99     lv_obj_t * top_margin_right_cluster = lv_demo_high_res_simple_container_create(top_margin, false, c->sz->gap[6],
100                                                                                    LV_FLEX_ALIGN_CENTER);
101 
102     lv_obj_t * wifi_icon = create_icon(top_margin_right_cluster, &c->top_margin_wifi_subject, NULL, c);
103     lv_image_set_src(wifi_icon, c->imgs[IMG_WIFI_ICON]);
104     lv_subject_add_observer_obj(&c->subject_groups.wifi.group, wifi_icon_observer_cb, wifi_icon, c);
105     lv_obj_t * wifi = create_wifi(lv_layer_sys(), c);
106     lv_obj_bind_flag_if_eq(wifi, &c->top_margin_wifi_subject, LV_OBJ_FLAG_HIDDEN, 0);
107     lv_obj_add_event_cb(wifi_icon, delete_modal_cb, LV_EVENT_DELETE, wifi);
108 
109     lv_obj_t * health_icon = create_icon(top_margin_right_cluster, &c->top_margin_health_subject, &c->imgs[IMG_HEALTH_ICON],
110                                          c);
111     lv_image_set_src(health_icon, c->imgs[lv_subject_get_int(&c->top_margin_health_subject) ? IMG_HEALTH_ICON_BOLD :
112                                           IMG_HEALTH_ICON]);
113     lv_obj_t * perfmon = create_perfmon(lv_layer_sys(), c);
114     lv_obj_bind_flag_if_eq(perfmon, &c->top_margin_health_subject, LV_OBJ_FLAG_HIDDEN, 0);
115     lv_obj_add_event_cb(health_icon, delete_modal_cb, LV_EVENT_DELETE, perfmon);
116 
117     lv_obj_t * settings_icon = create_icon(top_margin_right_cluster, &c->top_margin_setting_subject,
118                                            &c->imgs[IMG_SETTING_ICON], c);
119     lv_image_set_src(settings_icon, c->imgs[lv_subject_get_int(&c->top_margin_setting_subject) ? IMG_SETTING_ICON_BOLD :
120                                             IMG_SETTING_ICON]);
121     lv_obj_t * settings = create_settings(lv_layer_sys(), c);
122     lv_obj_bind_flag_if_eq(settings, &c->top_margin_setting_subject, LV_OBJ_FLAG_HIDDEN, 0);
123     lv_obj_add_event_cb(settings_icon, delete_modal_cb, LV_EVENT_DELETE, settings);
124 
125     lv_obj_update_layout(top_margin_right_cluster);
126     lv_obj_align_to(wifi, wifi_icon, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0);
127     lv_obj_align_to(perfmon, health_icon, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0);
128     lv_obj_align_to(settings, settings_icon, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0);
129 
130     return top_margin;
131 }
132 
lv_demo_high_res_top_margin_deinit_subjects(lv_demo_high_res_ctx_t * c)133 void lv_demo_high_res_top_margin_deinit_subjects(lv_demo_high_res_ctx_t * c)
134 {
135     if(!c->top_margin_subjects_are_init) return;
136     c->top_margin_subjects_are_init = false;
137     lv_subject_deinit(&c->top_margin_wifi_subject);
138     lv_subject_deinit(&c->top_margin_health_subject);
139     lv_subject_deinit(&c->top_margin_setting_subject);
140 }
141 
142 /**********************
143  *   STATIC FUNCTIONS
144  **********************/
145 
logout_cb(lv_event_t * e)146 static void logout_cb(lv_event_t * e)
147 {
148     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
149     if(c->exit_cb) c->exit_cb(&c->api);
150 }
151 
create_icon(lv_obj_t * parent,lv_subject_t * subject,lv_image_dsc_t ** img_dsc_pair,lv_demo_high_res_ctx_t * c)152 static lv_obj_t * create_icon(lv_obj_t * parent, lv_subject_t * subject, lv_image_dsc_t ** img_dsc_pair,
153                               lv_demo_high_res_ctx_t * c)
154 {
155     lv_obj_t * icon = lv_image_create(parent);
156     lv_obj_add_style(icon, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_A8_IMG], 0);
157     subject->user_data = icon;
158     lv_obj_set_user_data(icon, img_dsc_pair);
159     lv_obj_add_flag(icon, LV_OBJ_FLAG_CLICKABLE);
160     lv_obj_add_event_cb(icon, icon_clicked_cb, LV_EVENT_CLICKED, c);
161     return icon;
162 }
163 
delete_modal_cb(lv_event_t * e)164 static void delete_modal_cb(lv_event_t * e)
165 {
166     if(lv_layer_sys() == NULL) return;
167     lv_obj_t * modal = lv_event_get_user_data(e);
168     lv_obj_delete(modal);
169 }
170 
icon_clicked_cb(lv_event_t * e)171 static void icon_clicked_cb(lv_event_t * e)
172 {
173     lv_obj_t * clicked_icon = lv_event_get_target_obj(e);
174     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
175     lv_subject_t * icon_subjects[] = {
176         &c->top_margin_wifi_subject,
177         &c->top_margin_health_subject,
178         &c->top_margin_setting_subject
179     };
180     for(int32_t i = 0; i < (int32_t)ARRAY_LEN(icon_subjects); i++) {
181         lv_subject_t * subject = icon_subjects[i];
182         lv_obj_t * icon = subject->user_data;
183         lv_image_dsc_t ** pair = lv_obj_get_user_data(icon);
184         int32_t value = icon == clicked_icon && !lv_subject_get_int(subject);
185         lv_subject_set_int(subject, value);
186         if(pair) lv_image_set_src(icon, pair[value]);
187         if(value) {
188             lv_obj_add_flag(lv_layer_sys(), LV_OBJ_FLAG_CLICKABLE);
189             lv_obj_add_event_cb(lv_layer_sys(), sys_layer_clicked_cb, LV_EVENT_CLICKED, clicked_icon);
190         }
191     }
192 }
193 
sys_layer_clicked_cb(lv_event_t * e)194 static void sys_layer_clicked_cb(lv_event_t * e)
195 {
196     lv_obj_remove_event_cb(lv_layer_sys(), sys_layer_clicked_cb);
197     lv_obj_remove_flag(lv_layer_sys(), LV_OBJ_FLAG_CLICKABLE);
198 
199     lv_obj_t * relevant_icon = lv_event_get_user_data(e);
200     lv_obj_send_event(relevant_icon, LV_EVENT_CLICKED, NULL);
201 }
202 
wifi_ssid_ip_observer_cb(lv_observer_t * observer,lv_subject_t * subject)203 static void wifi_ssid_ip_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
204 {
205     lv_obj_t * label = lv_observer_get_target_obj(observer);
206     const char * ssid_ip = lv_observer_get_user_data(observer);
207     const char * ssid_ip_value = lv_subject_get_pointer(subject);
208     if(ssid_ip_value) {
209         lv_label_set_text_fmt(label, "%s: %s", ssid_ip, ssid_ip_value);
210     }
211     else {
212         lv_label_set_text_fmt(label, "%s: (offline)", ssid_ip);
213     }
214 }
215 
create_wifi(lv_obj_t * parent,lv_demo_high_res_ctx_t * c)216 static lv_obj_t * create_wifi(lv_obj_t * parent, lv_demo_high_res_ctx_t * c)
217 {
218     lv_obj_t * settings = lv_obj_create(parent);
219     lv_obj_remove_style_all(settings);
220     lv_obj_add_flag(settings, LV_OBJ_FLAG_FLOATING);
221     lv_obj_set_style_bg_opa(settings, LV_OPA_COVER, 0);
222     lv_obj_set_style_radius(settings, c->sz->gap[3], 0);
223     lv_obj_set_size(settings, c->sz->settings_panel_width, LV_SIZE_CONTENT);
224     lv_obj_set_style_pad_all(settings, c->sz->gap[7], 0);
225     lv_obj_add_style(settings, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_OBJ], 0);
226 
227     lv_obj_t * cont = lv_demo_high_res_simple_container_create(settings, true, c->sz->gap[4], LV_FLEX_ALIGN_START);
228     lv_obj_set_width(cont, LV_PCT(100));
229 
230     lv_obj_t * ssid = lv_label_create(cont);
231     lv_obj_add_style(ssid, &c->fonts[FONT_LABEL_XS], 0);
232     lv_obj_add_style(ssid, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
233     lv_subject_add_observer_obj(&c->api.subjects.wifi_ssid, wifi_ssid_ip_observer_cb, ssid, (void *)"SSID");
234     lv_obj_t * ip = lv_label_create(cont);
235     lv_obj_add_style(ip, &c->fonts[FONT_LABEL_XS], 0);
236     lv_obj_add_style(ip, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
237     lv_subject_add_observer_obj(&c->api.subjects.wifi_ip, wifi_ssid_ip_observer_cb, ip, (void *)"IP");
238 
239     return settings;
240 }
241 
wifi_icon_observer_cb(lv_observer_t * observer,lv_subject_t * subject)242 static void wifi_icon_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
243 {
244     LV_UNUSED(subject);
245     lv_obj_t * wifi_icon = lv_observer_get_target_obj(observer);
246     lv_demo_high_res_ctx_t * c = lv_observer_get_user_data(observer);
247     lv_obj_set_style_opa(wifi_icon, lv_subject_get_pointer(&c->api.subjects.wifi_ssid)
248                          || lv_subject_get_pointer(&c->api.subjects.wifi_ip)
249                          ? LV_OPA_COVER : LV_OPA_50, 0);
250 }
251 
create_perfmon(lv_obj_t * parent,lv_demo_high_res_ctx_t * c)252 static lv_obj_t * create_perfmon(lv_obj_t * parent, lv_demo_high_res_ctx_t * c)
253 {
254     lv_obj_t * perfmon = lv_obj_create(parent);
255     lv_obj_add_flag(perfmon, LV_OBJ_FLAG_FLOATING);
256 
257     lv_obj_set_style_border_opa(perfmon, LV_OPA_TRANSP, 0);
258     lv_obj_set_style_radius(perfmon, c->sz->gap[3], 0);
259     lv_obj_set_size(perfmon, c->sz->health_panel_width, LV_SIZE_CONTENT);
260     lv_obj_set_style_pad_all(perfmon, c->sz->gap[7], 0);
261     lv_obj_add_style(perfmon, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_OBJ], 0);
262 
263     lv_obj_t * cont = lv_demo_high_res_simple_container_create(perfmon, true, 0, LV_FLEX_ALIGN_START);
264     lv_obj_set_width(cont, LV_PCT(100));
265     lv_obj_t * lab1 = lv_label_create(cont);
266     lv_obj_add_style(lab1, &c->fonts[FONT_LABEL_XS], 0);
267     lv_obj_add_style(lab1, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
268     lv_label_set_text(lab1, "Perf. monitor is not enabled");
269 
270 #if LV_USE_PERF_MONITOR
271     lv_obj_t * divider = lv_line_create(cont);
272     lv_obj_set_size(divider, LV_PCT(100), c->sz->gap[4]);
273     /* static const lv_point_precise_t points[] = {{LV_PCT(0), LV_PCT(50)}, {LV_PCT(100), LV_PCT(50)}}; */
274     /* lv_line_set_points(divider, points, 2); */
275     lv_obj_set_style_line_width(divider, 1, 0);
276     lv_obj_add_style(divider, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
277     lv_obj_set_style_line_opa(divider, LV_OPA_10, 0);
278     lv_obj_t * lab2 = lv_label_create(cont);
279     lv_obj_add_style(lab2, &c->fonts[FONT_LABEL_XS], 0);
280     lv_obj_add_style(lab2, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
281     lv_obj_t * lab3 = lv_label_create(cont);
282     lv_obj_add_style(lab3, &c->fonts[FONT_LABEL_XS], 0);
283     lv_obj_add_style(lab3, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
284     lv_obj_set_style_text_opa(lab3, LV_OPA_60, 0);
285 
286     lv_display_t * disp = lv_display_get_default();
287     lv_subject_add_observer_obj(&disp->perf_sysmon_backend.subject, perfmon_data_cb, cont, NULL);
288 #endif
289     return perfmon;
290 }
291 
292 #if LV_USE_PERF_MONITOR
perfmon_data_cb(lv_observer_t * observer,lv_subject_t * subject)293 static void perfmon_data_cb(lv_observer_t * observer, lv_subject_t * subject)
294 {
295     lv_obj_t * cont = lv_observer_get_target_obj(observer);
296     const lv_sysmon_perf_info_t * perf = lv_subject_get_pointer(subject);
297 
298     lv_obj_t * lab1 = lv_obj_get_child(cont, 0);
299     lv_obj_t * lab2 = lv_obj_get_child(cont, 2);
300     lv_obj_t * lab3 = lv_obj_get_child(cont, 3);
301 
302     lv_label_set_text_fmt(lab1, "%"PRIu32" FPS, %"PRIu32"%% CPU", perf->calculated.fps, perf->calculated.cpu);
303     lv_label_set_text_fmt(lab2, "Refresh: %"PRIu32"ms", perf->calculated.render_avg_time + perf->calculated.flush_avg_time);
304     lv_label_set_text_fmt(lab3, "Render / Flush: %"PRIu32"ms / %"PRIu32"ms", perf->calculated.render_avg_time,
305                           perf->calculated.flush_avg_time);
306 
307 }
308 #endif
309 
create_settings(lv_obj_t * parent,lv_demo_high_res_ctx_t * c)310 static lv_obj_t * create_settings(lv_obj_t * parent, lv_demo_high_res_ctx_t * c)
311 {
312     lv_obj_t * settings = lv_obj_create(parent);
313     lv_obj_remove_style_all(settings);
314     lv_obj_add_flag(settings, LV_OBJ_FLAG_FLOATING);
315     lv_obj_set_style_bg_opa(settings, LV_OPA_COVER, 0);
316     lv_obj_set_style_radius(settings, c->sz->gap[3], 0);
317     lv_obj_set_size(settings, c->sz->settings_panel_width, LV_SIZE_CONTENT);
318     lv_obj_set_style_pad_ver(settings, c->sz->gap[5], 0);
319     lv_obj_add_style(settings, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_OBJ], 0);
320 
321     lv_obj_set_flex_flow(settings, LV_FLEX_FLOW_COLUMN);
322 
323     lv_obj_t * temperature_label_cont = create_setting_label_cont(settings, "Temperature", c);
324     lv_obj_set_style_text_opa(lv_obj_get_child(temperature_label_cont, 0), LV_OPA_60, 0);
325 
326     lv_obj_t * celsius_label_cont = create_setting_label_cont(settings, "Celsius (\xc2\xb0""C)", c);
327     lv_obj_set_style_bg_opa(celsius_label_cont, 255 * lv_subject_get_int(&c->temperature_units_are_celsius), 0);
328 
329     lv_obj_t * fahrenheit_label_cont = create_setting_label_cont(settings, "Fahrenheit (\xc2\xb0""F)", c);
330     lv_obj_set_style_bg_opa(fahrenheit_label_cont, 255 * !lv_subject_get_int(&c->temperature_units_are_celsius), 0);
331 
332     lv_obj_add_event_cb(celsius_label_cont, setting_clicked_cb, LV_EVENT_CLICKED, c);
333     lv_obj_add_event_cb(fahrenheit_label_cont, setting_clicked_cb, LV_EVENT_CLICKED, c);
334 
335     return settings;
336 }
337 
create_setting_label_cont(lv_obj_t * parent,const char * text,lv_demo_high_res_ctx_t * c)338 static lv_obj_t * create_setting_label_cont(lv_obj_t * parent, const char * text, lv_demo_high_res_ctx_t * c)
339 {
340     lv_obj_t * label_cont = lv_obj_create(parent);
341     lv_obj_remove_style_all(label_cont);
342     lv_obj_set_size(label_cont, LV_PCT(100), c->sz->icon[1]);
343     lv_obj_set_style_bg_color(label_cont, lv_color_hex(0xCC0000), 0);
344     lv_obj_set_style_pad_left(label_cont, c->sz->gap[7], 0);
345 
346     lv_obj_t * label = lv_label_create(label_cont);
347     lv_label_set_text_static(label, text);
348     lv_obj_add_style(label, &c->fonts[FONT_LABEL_SM], 0);
349     lv_obj_add_style(label, &c->styles[STYLE_COLOR_BASE][STYLE_TYPE_TEXT], 0);
350     lv_obj_set_align(label, LV_ALIGN_LEFT_MID);
351 
352     return label_cont;
353 }
354 
setting_clicked_cb(lv_event_t * e)355 static void setting_clicked_cb(lv_event_t * e)
356 {
357     lv_obj_t * obj = lv_event_get_target_obj(e);
358     lv_obj_t * parent = lv_obj_get_parent(obj);
359     lv_demo_high_res_ctx_t * c = lv_event_get_user_data(e);
360     lv_obj_t * celsius = lv_obj_get_child(parent, 1);
361     lv_obj_t * fahrenheit = lv_obj_get_child(parent, 2);
362     if(obj == celsius) {
363         lv_obj_set_style_bg_opa(celsius, LV_OPA_COVER, 0);
364         lv_obj_set_style_bg_opa(fahrenheit, LV_OPA_TRANSP, 0);
365         lv_subject_set_int(&c->temperature_units_are_celsius, 1);
366     }
367     else {
368         lv_obj_set_style_bg_opa(fahrenheit, LV_OPA_COVER, 0);
369         lv_obj_set_style_bg_opa(celsius, LV_OPA_TRANSP, 0);
370         lv_subject_set_int(&c->temperature_units_are_celsius, 0);
371     }
372 }
373 
date_observer_cb(lv_observer_t * observer,lv_subject_t * subject)374 static void date_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
375 {
376     LV_UNUSED(subject);
377     lv_obj_t * date_label = lv_observer_get_target_obj(observer);
378     lv_demo_high_res_ctx_t * c = lv_observer_get_user_data(observer);
379 
380     lv_label_set_text_fmt(date_label, "%s, %"PRId32" %s",
381                           (char *)lv_subject_get_pointer(&c->api.subjects.week_day_name),
382                           lv_subject_get_int(&c->api.subjects.month_day),
383                           (char *)lv_subject_get_pointer(&c->api.subjects.month_name));
384 }
385 
time_observer_cb(lv_observer_t * observer,lv_subject_t * subject)386 static void time_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
387 {
388     LV_UNUSED(subject);
389     lv_obj_t * time_label = lv_observer_get_target_obj(observer);
390     lv_demo_high_res_ctx_t * c = lv_observer_get_user_data(observer);
391 
392     lv_label_set_text_fmt(time_label, "%02d:%02d", lv_subject_get_int(&c->api.subjects.hour),
393                           lv_subject_get_int(&c->api.subjects.minute));
394 }
395 
396 #endif /*LV_USE_DEMO_HIGH_RES*/
397