1 /**
2  * @file lv_demo_high_res_util.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/canvas/lv_canvas.h"
15 #include "../../src/widgets/label/lv_label.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 
25 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_12)
26 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_16)
27 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_24)
28 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_30)
29 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_36)
30 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_60)
31 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_120)
32 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_160)
33 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_30)
34 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_60)
35 
36 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_20)
37 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_40)
38 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_45)
39 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_regular_90)
40 
41 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_80)
42 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_107)
43 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_180)
44 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_light_240)
45 
46 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_8)
47 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_11)
48 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_18)
49 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_medium_36)
50 
51 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_20)
52 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_24)
53 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_40)
54 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_45)
55 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_54)
56 LV_FONT_DECLARE(font_lv_demo_high_res_roboto_slab_bold_90)
57 
58 /**********************
59  *  STATIC PROTOTYPES
60  **********************/
61 
62 static void init_fonts_sm(lv_style_t * fonts);
63 static void init_fonts_md(lv_style_t * fonts);
64 static void init_fonts_lg(lv_style_t * fonts);
65 static void theme_observer_cb(lv_observer_t * observer, lv_subject_t * subject);
66 static void free_ctx_event_cb(lv_event_t * e);
67 static void label_text_temperature_cb(lv_observer_t * observer, lv_subject_t * subject);
68 
69 /**********************
70  *  STATIC PROTOTYPES
71  **********************/
72 
73 /**********************
74  *  STATIC VARIABLES
75  **********************/
76 
77 const lv_demo_high_res_theme_t lv_demo_high_res_theme_light = {
78     .base = LV_COLOR_MAKE(0xff, 0xff, 0xff),
79     .accent = LV_COLOR_MAKE(0xcc, 0x00, 0x00),
80 };
81 
82 const lv_demo_high_res_theme_t lv_demo_high_res_theme_dark = {
83     .base = LV_COLOR_MAKE(0x00, 0x00, 0x00),
84     .accent = LV_COLOR_MAKE(0xe1, 0x2b, 0x17),
85 };
86 
87 const lv_demo_high_res_sizes_t lv_demo_high_res_sizes_all[SIZE_COUNT] = {
88     {
89         .gap = {0, 2, 4, 6, 9, 12, 14, 16, 20, 24, 32},
90         .icon = {16, 21, 32, 42, 64},
91         .card_long_edge = 200,
92         .widget_long_edge = 256,
93         .card_short_edge = 120,
94         .smart_home_arc_diameter = 107,
95         .ev_charging_arc_diameter = 160,
96         .smart_meter_collapsed_part_height = 48,
97         .slider_width = 27,
98         .small_chart_height = 67,
99         .large_chart_height = 167,
100         .card_radius = 12,
101         .health_panel_width = 133,
102         .settings_panel_width = 179,
103         .home_bottom_margin_height = 53,
104         .init_fonts_cb = init_fonts_sm
105     },
106     {
107         .gap = {0, 3, 6, 9, 12, 16, 20, 24, 30, 36, 48},
108         .icon = {24, 32, 48, 64, 96},
109         .card_long_edge = 300,
110         .widget_long_edge = 384,
111         .card_short_edge = 180,
112         .smart_home_arc_diameter = 160,
113         .ev_charging_arc_diameter = 240,
114         .smart_meter_collapsed_part_height = 72,
115         .slider_width = 40,
116         .small_chart_height = 100,
117         .large_chart_height = 250,
118         .card_radius = 18,
119         .health_panel_width = 200,
120         .settings_panel_width = 268,
121         .home_bottom_margin_height = 80,
122         .init_fonts_cb = init_fonts_md
123     },
124     {
125         .gap = {0, 5, 10, 15, 18, 24, 30, 36, 45, 54, 72},
126         .icon = {36, 48, 72, 96, 144},
127         .card_long_edge = 450,
128         .widget_long_edge = 576,
129         .card_short_edge = 270,
130         .smart_home_arc_diameter = 240,
131         .ev_charging_arc_diameter = 360,
132         .smart_meter_collapsed_part_height = 108,
133         .slider_width = 60,
134         .small_chart_height = 150,
135         .large_chart_height = 375,
136         .card_radius = 27,
137         .health_panel_width = 300,
138         .settings_panel_width = 402,
139         .home_bottom_margin_height = 120,
140         .init_fonts_cb = init_fonts_lg
141     }
142 };
143 
144 /**********************
145  *      MACROS
146  **********************/
147 
148 #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(*arr))
149 
150 /**********************
151  *   GLOBAL FUNCTIONS
152  **********************/
153 
lv_demo_high_res_base_obj_create(const char * assets_path,const char * logo_path,const char * slides_path,lv_demo_high_res_exit_cb_t exit_cb)154 lv_obj_t * lv_demo_high_res_base_obj_create(const char * assets_path,
155                                             const char * logo_path,
156                                             const char * slides_path,
157                                             lv_demo_high_res_exit_cb_t exit_cb)
158 {
159     lv_demo_high_res_ctx_t * c = lv_malloc_zeroed(sizeof(lv_demo_high_res_ctx_t));
160     LV_ASSERT_MALLOC(c);
161     lv_obj_t * base_obj = lv_obj_create(lv_screen_active());
162     lv_obj_set_user_data(base_obj, c);
163     lv_obj_add_event_cb(base_obj, free_ctx_event_cb, LV_EVENT_DELETE, NULL);
164 
165     lv_display_t * disp = lv_display_get_default();
166     int32_t hres = lv_display_get_horizontal_resolution(disp);
167     int32_t vres = lv_display_get_vertical_resolution(disp);
168     bool is_exact;
169     int32_t size;
170     if(hres < 1280 && vres < 720) {
171         is_exact = hres == 800 && vres == 480;
172         size = SIZE_SM;
173     }
174     else if(hres < 1920 && vres < 1080) {
175         is_exact = hres == 1280 && vres == 720;
176         size = SIZE_MD;
177     }
178     else {
179         is_exact = hres == 1920 && vres == 1080;
180         size = SIZE_LG;
181     }
182     if(!is_exact) {
183         LV_LOG_WARN("a display size of exactly 800x480, 1280x720, or 1920x1080 is recommended for the high-res demo");
184     }
185     c->sz = &lv_demo_high_res_sizes_all[size];
186 
187     static const struct {
188         const char * name;
189         lv_color_format_t cf;
190     } image_details[IMG_COUNT] = {
191         {"about_app_icon", LV_COLOR_FORMAT_ARGB8888},
192         {"album_art", LV_COLOR_FORMAT_ARGB8888},
193         {"arrow_left", LV_COLOR_FORMAT_ARGB8888},
194         {"backward_icon", LV_COLOR_FORMAT_ARGB8888},
195         {"cold_icon", LV_COLOR_FORMAT_ARGB8888},
196         {"dry_icon", LV_COLOR_FORMAT_ARGB8888},
197         {"energy_icon", LV_COLOR_FORMAT_ARGB8888},
198         {"ev_charging_app_icon", LV_COLOR_FORMAT_ARGB8888},
199         {"ev_charging_widget3_1_bg", LV_COLOR_FORMAT_ARGB8888},
200         {"ev_charging_widget3_bg", LV_COLOR_FORMAT_ARGB8888},
201         {"fan", LV_COLOR_FORMAT_ARGB8888},
202         {"forward_icon", LV_COLOR_FORMAT_ARGB8888},
203         {"health_icon", LV_COLOR_FORMAT_ARGB8888},
204         {"health_icon_bold", LV_COLOR_FORMAT_ARGB8888},
205         {"heat_icon", LV_COLOR_FORMAT_ARGB8888},
206         {"lamp", LV_COLOR_FORMAT_ARGB8888},
207         {"logout_icon", LV_COLOR_FORMAT_ARGB8888},
208         {"main_light_slider", LV_COLOR_FORMAT_ARGB8888},
209         {"minus", LV_COLOR_FORMAT_ARGB8888},
210         {"pager_left", LV_COLOR_FORMAT_ARGB8888},
211         {"pager_pause", LV_COLOR_FORMAT_ARGB8888},
212         {"pager_play", LV_COLOR_FORMAT_ARGB8888},
213         {"pager_right", LV_COLOR_FORMAT_ARGB8888},
214         {"play_icon", LV_COLOR_FORMAT_ARGB8888},
215         {"play_icon_1", LV_COLOR_FORMAT_ARGB8888},
216         {"plus", LV_COLOR_FORMAT_ARGB8888},
217         {"range_icon", LV_COLOR_FORMAT_ARGB8888},
218         {"setting_icon", LV_COLOR_FORMAT_ARGB8888},
219         {"setting_icon_bold", LV_COLOR_FORMAT_ARGB8888},
220         {"smart_home_app_icon", LV_COLOR_FORMAT_ARGB8888},
221         {"smart_home_widget1_bg", LV_COLOR_FORMAT_ARGB8888},
222         {"smart_home_widget2_bg", LV_COLOR_FORMAT_ARGB8888},
223         {"smart_meter_app_icon", LV_COLOR_FORMAT_ARGB8888},
224         {"thermostat_app_icon", LV_COLOR_FORMAT_ARGB8888},
225         {"time_icon", LV_COLOR_FORMAT_ARGB8888},
226         {"unlock", LV_COLOR_FORMAT_ARGB8888},
227         {"volume", LV_COLOR_FORMAT_ARGB8888},
228         {"weather", LV_COLOR_FORMAT_ARGB8888},
229         {"wifi_icon", LV_COLOR_FORMAT_ARGB8888},
230         {"light_bg_about", LV_COLOR_FORMAT_NATIVE},
231         {"dark_bg_about", LV_COLOR_FORMAT_NATIVE},
232         {"light_bg_ev_charging", LV_COLOR_FORMAT_NATIVE},
233         {"dark_bg_ev_charging", LV_COLOR_FORMAT_NATIVE},
234         {"light_bg_home", LV_COLOR_FORMAT_NATIVE},
235         {"dark_bg_home", LV_COLOR_FORMAT_NATIVE},
236         {"light_bg_smart_home", LV_COLOR_FORMAT_NATIVE},
237         {"dark_bg_smart_home", LV_COLOR_FORMAT_NATIVE},
238         {"light_bg_smart_meter", LV_COLOR_FORMAT_NATIVE},
239         {"dark_bg_smart_meter", LV_COLOR_FORMAT_NATIVE},
240         {"light_bg_thermostat", LV_COLOR_FORMAT_NATIVE},
241         {"dark_bg_thermostat", LV_COLOR_FORMAT_NATIVE},
242         {"light_dark_theme_icon", LV_COLOR_FORMAT_ARGB8888},
243         {"dark_dark_theme_icon", LV_COLOR_FORMAT_ARGB8888},
244         {"light_light_theme_icon", LV_COLOR_FORMAT_ARGB8888},
245         {"dark_light_theme_icon", LV_COLOR_FORMAT_ARGB8888},
246         {"light_widget1_bg", LV_COLOR_FORMAT_ARGB8888},
247         {"dark_widget1_bg", LV_COLOR_FORMAT_ARGB8888},
248         {"light_widget2_bg", LV_COLOR_FORMAT_ARGB8888},
249         {"dark_widget2_bg", LV_COLOR_FORMAT_ARGB8888},
250         {"light_widget3_bg", LV_COLOR_FORMAT_ARGB8888},
251         {"dark_widget3_bg", LV_COLOR_FORMAT_ARGB8888},
252         {"light_widget4_bg", LV_COLOR_FORMAT_ARGB8888},
253         {"dark_widget4_bg", LV_COLOR_FORMAT_ARGB8888},
254         {"light_widget5_bg", LV_COLOR_FORMAT_ARGB8888},
255         {"dark_widget5_bg", LV_COLOR_FORMAT_ARGB8888},
256     };
257     const char * size_prefix = size == SIZE_SM ? "sm" : size == SIZE_MD ? "md" : "lg";
258     for(uint32_t i = 0; i < IMG_COUNT; i++) {
259         char path_buf[256];
260         int chars = lv_snprintf(path_buf, sizeof(path_buf), "%s/img_lv_demo_high_res_%s_%s.png",
261                                 assets_path, image_details[i].name, size_prefix);
262         LV_ASSERT(chars < (int)sizeof(path_buf));
263         c->imgs[i] = lv_demo_high_res_image_preload(path_buf, image_details[i].cf, LV_SCALE_NONE);
264     }
265 
266     for(uint32_t i = 0; i < STYLE_COLOR_COUNT; i++) {
267         for(uint32_t j = 0; j < STYLE_TYPE_COUNT; j++) {
268             lv_style_init(&c->styles[i][j]);
269         }
270     }
271 
272     for(uint32_t i = 0; i < FONT_COUNT; i++) {
273         lv_style_init(&c->fonts[i]);
274     }
275     c->sz->init_fonts_cb(c->fonts);
276 
277     lv_subject_init_pointer(&c->th, (void *)&lv_demo_high_res_theme_dark);
278     c->th.user_data = c;
279     lv_subject_add_observer(&c->th, theme_observer_cb, c);
280 
281     c->logo_path = lv_strdup(logo_path);
282     LV_ASSERT_MALLOC(c->logo_path);
283     c->slides_path = lv_strdup(slides_path);
284     LV_ASSERT_MALLOC(c->slides_path);
285 
286     c->exit_cb = exit_cb;
287 
288     lv_subject_init_int(&c->temperature_units_are_celsius, 1);
289     c->ev_charging_bg_cont = NULL;
290     lv_subject_init_int(&c->ev_charging_progress, EV_CHARGING_RANGE_END * 0 / 100);
291     lv_subject_init_int(&c->smart_meter_selected_bar, 4);
292 
293     c->top_margin_subjects_are_init = false;
294 
295     /* API subjects */
296 
297     /* input subjects */
298     lv_subject_init_int(&c->api.subjects.hour, 9);
299     lv_subject_init_int(&c->api.subjects.minute, 36);
300     lv_subject_init_pointer(&c->api.subjects.week_day_name, "Tuesday");
301     lv_subject_init_int(&c->api.subjects.month_day, 31);
302     lv_subject_init_pointer(&c->api.subjects.month_name, "October");
303     lv_subject_init_int(&c->api.subjects.temperature_outdoor, 140); /* tenths of a degree */
304     lv_subject_init_int(&c->api.subjects.temperature_indoor, 225); /* tenths of a degree */
305     lv_subject_init_pointer(&c->api.subjects.wifi_ssid, NULL);
306     lv_subject_init_pointer(&c->api.subjects.wifi_ip, NULL);
307 
308     /* output subjects */
309     lv_subject_init_int(&c->api.subjects.music_play, 1);
310 
311     /* input+output subjects */
312     lv_subject_init_int(&c->api.subjects.locked, 0);
313     lv_subject_init_int(&c->api.subjects.volume, 63);
314     lv_subject_init_int(&c->api.subjects.main_light_temperature, 4000);
315     lv_subject_init_int(&c->api.subjects.main_light_intensity, 52);
316     lv_subject_init_int(&c->api.subjects.thermostat_fan_speed, 40);
317     lv_subject_init_int(&c->api.subjects.thermostat_target_temperature, 240); /* tenths of a degree */
318 
319     c->api.base_obj = base_obj;
320     c->api.user_data = NULL;
321 
322     c->subject_groups.time.members[0] = &c->api.subjects.hour;
323     c->subject_groups.time.members[1] = &c->api.subjects.minute;
324     lv_subject_init_group(&c->subject_groups.time.group, c->subject_groups.time.members,
325                           ARRAY_LEN(c->subject_groups.time.members));
326     c->subject_groups.date.members[0] = &c->api.subjects.week_day_name;
327     c->subject_groups.date.members[1] = &c->api.subjects.month_day;
328     c->subject_groups.date.members[2] = &c->api.subjects.month_name;
329     lv_subject_init_group(&c->subject_groups.date.group, c->subject_groups.date.members,
330                           ARRAY_LEN(c->subject_groups.date.members));
331     c->subject_groups.wifi.members[0] = &c->api.subjects.wifi_ssid;
332     c->subject_groups.wifi.members[1] = &c->api.subjects.wifi_ip;
333     lv_subject_init_group(&c->subject_groups.wifi.group, c->subject_groups.wifi.members,
334                           ARRAY_LEN(c->subject_groups.wifi.members));
335 
336     lv_array_init(&c->about_slides_array, 1, sizeof(lv_image_dsc_t *));
337     lv_fs_dir_t dir;
338     lv_fs_res_t fs_res = lv_fs_dir_open(&dir, slides_path);
339     if(fs_res == LV_FS_RES_OK) {
340         fs_res = lv_fs_dir_close(&dir);
341         LV_ASSERT(fs_res == LV_FS_RES_OK);
342 
343         c->about_slides_dir_exists = true;
344 
345         for(int32_t i = 1; ; i++) {
346             char buf[256];
347             lv_snprintf(buf, sizeof(buf), "%s/Slide%"LV_PRId32".png", slides_path, i);
348             lv_fs_file_t file;
349             fs_res = lv_fs_open(&file, buf, LV_FS_MODE_RD);
350             if(fs_res != LV_FS_RES_OK) {
351                 break;
352             }
353             fs_res = lv_fs_close(&file);
354             LV_ASSERT(fs_res == LV_FS_RES_OK);
355 
356             lv_image_header_t header;
357             lv_result_t res = lv_image_decoder_get_info(buf, &header);
358             if(res == LV_RESULT_INVALID) {
359                 LV_LOG_WARN("Couldn't read the header info of slide image");
360                 continue;
361             }
362             /* the ratio of a slide's height to the display's height will be 9:16 */
363             int32_t scale = (9 * 256 * vres) / (16 * header.h);
364 
365             lv_image_dsc_t * loaded_draw_buf = lv_demo_high_res_image_preload(buf, LV_COLOR_FORMAT_NATIVE, scale);
366             if(loaded_draw_buf == NULL) continue;
367             lv_array_push_back(&c->about_slides_array, &loaded_draw_buf);
368 
369             if(scale != LV_SCALE_NONE) LV_LOG_INFO("A slide was scaled by %"LV_PRId32" (256 means 1:1)", scale);
370         }
371     }
372 
373     return base_obj;
374 }
375 
lv_demo_high_res_simple_container_create(lv_obj_t * parent,bool vertical,int32_t pad,lv_flex_align_t align_cross_place)376 lv_obj_t * lv_demo_high_res_simple_container_create(lv_obj_t * parent, bool vertical, int32_t pad,
377                                                     lv_flex_align_t align_cross_place)
378 {
379     lv_obj_t * obj = lv_obj_create(parent);
380     lv_obj_remove_style_all(obj);
381     lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
382     if(vertical) {
383         lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
384         lv_obj_set_style_pad_row(obj, pad, 0);
385     }
386     else {
387         lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
388         lv_obj_set_style_pad_column(obj, pad, 0);
389     }
390     lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, align_cross_place, align_cross_place);
391     return obj;
392 }
393 
lv_demo_high_res_label_bind_temperature(lv_obj_t * label,lv_subject_t * subject,lv_demo_high_res_ctx_t * c)394 void lv_demo_high_res_label_bind_temperature(lv_obj_t * label, lv_subject_t * subject, lv_demo_high_res_ctx_t * c)
395 {
396     lv_obj_set_user_data(label, c);
397     lv_subject_add_observer_obj(subject, label_text_temperature_cb, label, subject);
398     lv_subject_add_observer_obj(&c->temperature_units_are_celsius, label_text_temperature_cb, label, subject);
399 }
400 
lv_demo_high_res_theme_observer_image_src_cb(lv_observer_t * observer,lv_subject_t * subject)401 void lv_demo_high_res_theme_observer_image_src_cb(lv_observer_t * observer, lv_subject_t * subject)
402 {
403     lv_obj_t * obj = lv_observer_get_target_obj(observer);
404     lv_image_dsc_t ** pair = lv_observer_get_user_data(observer);
405 
406     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(subject);
407 
408     if(th == &lv_demo_high_res_theme_light) {
409         lv_image_set_src(obj, pair[0]);
410     }
411     else {
412         lv_image_set_src(obj, pair[1]);
413     }
414 }
415 
lv_demo_high_res_theme_observer_obj_bg_image_src_cb(lv_observer_t * observer,lv_subject_t * subject)416 void lv_demo_high_res_theme_observer_obj_bg_image_src_cb(lv_observer_t * observer, lv_subject_t * subject)
417 {
418     lv_obj_t * obj = lv_observer_get_target_obj(observer);
419     lv_image_dsc_t ** pair = lv_observer_get_user_data(observer);
420 
421     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(subject);
422 
423     if(th == &lv_demo_high_res_theme_light) {
424         lv_obj_set_style_bg_image_src(obj, pair[0], 0);
425     }
426     else {
427         lv_obj_set_style_bg_image_src(obj, pair[1], 0);
428     }
429 }
430 
lv_demo_high_res_image_preload(const void * src,lv_color_format_t cf,int32_t scale)431 lv_image_dsc_t * lv_demo_high_res_image_preload(const void * src, lv_color_format_t cf, int32_t scale)
432 {
433     lv_image_header_t header;
434     lv_result_t res = lv_image_decoder_get_info(src, &header);
435     if(res == LV_RESULT_INVALID) {
436         LV_LOG_WARN("Couldn't read the header info of source");
437         return NULL;
438     }
439 
440     lv_draw_buf_t * dest;
441     int32_t dest_w = header.w * scale / 256;
442     int32_t dest_h = header.h * scale / 256;
443     dest = lv_draw_buf_create(dest_w, dest_h, cf, LV_STRIDE_AUTO);
444 
445     lv_obj_t * canvas = lv_canvas_create(lv_screen_active());
446     lv_canvas_set_draw_buf(canvas, dest);
447     lv_canvas_fill_bg(canvas, lv_color_hex3(0x000), LV_OPA_TRANSP);
448 
449     lv_layer_t layer;
450     lv_canvas_init_layer(canvas, &layer);
451 
452     lv_draw_image_dsc_t dsc;
453     lv_draw_image_dsc_init(&dsc);
454     dsc.src = src;
455     dsc.scale_x = scale;
456     dsc.scale_y = scale;
457 
458     lv_area_t coords = {0, 0, header.w - 1, header.h - 1};
459     lv_draw_image(&layer, &dsc, &coords);
460     lv_canvas_finish_layer(canvas, &layer);
461 
462     lv_obj_delete(canvas);
463 
464     return (lv_image_dsc_t *) dest;
465 }
466 
467 /**********************
468  *   STATIC FUNCTIONS
469  **********************/
470 
init_fonts_sm(lv_style_t * fonts)471 static void init_fonts_sm(lv_style_t * fonts)
472 {
473     lv_style_set_text_font(&fonts[FONT_HEADING_MD], &font_lv_demo_high_res_roboto_slab_regular_20);
474     lv_style_set_text_font(&fonts[FONT_HEADING_LG], &font_lv_demo_high_res_roboto_slab_regular_40);
475     lv_style_set_text_font(&fonts[FONT_HEADING_XL], &font_lv_demo_high_res_roboto_slab_light_80);
476     lv_style_set_text_font(&fonts[FONT_HEADING_XXL], &font_lv_demo_high_res_roboto_slab_light_107);
477     lv_style_set_text_font(&fonts[FONT_LABEL_XS], &font_lv_demo_high_res_roboto_medium_8);
478     lv_style_set_text_line_space(&fonts[FONT_LABEL_XS],
479                                  30 * lv_font_get_line_height(&font_lv_demo_high_res_roboto_medium_8) / 100); /* +30% */
480     /* lv_style_set_text_letter_space(&fonts[FONT_LABEL_XS], 197 * lv_font_get_letter_space(&font_lv_demo_high_res_roboto_medium_8) / 200); */ /* -1.5% */
481     lv_style_set_text_font(&fonts[FONT_LABEL_SM], &font_lv_demo_high_res_roboto_medium_11);
482     lv_style_set_text_font(&fonts[FONT_LABEL_MD], &font_lv_demo_high_res_roboto_medium_16);
483     lv_style_set_text_font(&fonts[FONT_LABEL_LG], &font_lv_demo_high_res_roboto_slab_bold_20);
484     lv_style_set_text_font(&fonts[FONT_LABEL_XL], &font_lv_demo_high_res_roboto_slab_bold_24);
485     lv_style_set_text_font(&fonts[FONT_LABEL_2XL], &font_lv_demo_high_res_roboto_slab_bold_40);
486 }
487 
init_fonts_md(lv_style_t * fonts)488 static void init_fonts_md(lv_style_t * fonts)
489 {
490     lv_style_set_text_font(&fonts[FONT_HEADING_MD], &font_lv_demo_high_res_roboto_slab_regular_30);
491     lv_style_set_text_font(&fonts[FONT_HEADING_LG], &font_lv_demo_high_res_roboto_slab_regular_60);
492     lv_style_set_text_font(&fonts[FONT_HEADING_XL], &font_lv_demo_high_res_roboto_slab_light_120);
493     lv_style_set_text_font(&fonts[FONT_HEADING_XXL], &font_lv_demo_high_res_roboto_slab_light_160);
494     lv_style_set_text_font(&fonts[FONT_LABEL_XS], &font_lv_demo_high_res_roboto_medium_12);
495     lv_style_set_text_line_space(&fonts[FONT_LABEL_XS],
496                                  30 * lv_font_get_line_height(&font_lv_demo_high_res_roboto_medium_12) / 100); /* +30% */
497     /* lv_style_set_text_letter_space(&fonts[FONT_LABEL_XS], 197 * lv_font_get_letter_space(&font_lv_demo_high_res_roboto_medium_12) / 200); */ /* -1.5% */
498     lv_style_set_text_font(&fonts[FONT_LABEL_SM], &font_lv_demo_high_res_roboto_medium_16);
499     lv_style_set_text_font(&fonts[FONT_LABEL_MD], &font_lv_demo_high_res_roboto_medium_24);
500     lv_style_set_text_font(&fonts[FONT_LABEL_LG], &font_lv_demo_high_res_roboto_slab_bold_30);
501     lv_style_set_text_font(&fonts[FONT_LABEL_XL], &font_lv_demo_high_res_roboto_slab_bold_36);
502     lv_style_set_text_font(&fonts[FONT_LABEL_2XL], &font_lv_demo_high_res_roboto_slab_bold_60);
503 }
504 
init_fonts_lg(lv_style_t * fonts)505 static void init_fonts_lg(lv_style_t * fonts)
506 {
507     lv_style_set_text_font(&fonts[FONT_HEADING_MD], &font_lv_demo_high_res_roboto_slab_regular_45);
508     lv_style_set_text_font(&fonts[FONT_HEADING_LG], &font_lv_demo_high_res_roboto_slab_regular_90);
509     lv_style_set_text_font(&fonts[FONT_HEADING_XL], &font_lv_demo_high_res_roboto_slab_light_180);
510     lv_style_set_text_font(&fonts[FONT_HEADING_XXL], &font_lv_demo_high_res_roboto_slab_light_240);
511     lv_style_set_text_font(&fonts[FONT_LABEL_XS], &font_lv_demo_high_res_roboto_medium_18);
512     lv_style_set_text_line_space(&fonts[FONT_LABEL_XS],
513                                  30 * lv_font_get_line_height(&font_lv_demo_high_res_roboto_medium_18) / 100); /* +30% */
514     /* lv_style_set_text_letter_space(&fonts[FONT_LABEL_XS], 197 * lv_font_get_letter_space(&font_lv_demo_high_res_roboto_medium_18) / 200); */ /* -1.5% */
515     lv_style_set_text_font(&fonts[FONT_LABEL_SM], &font_lv_demo_high_res_roboto_medium_24);
516     lv_style_set_text_font(&fonts[FONT_LABEL_MD], &font_lv_demo_high_res_roboto_medium_36);
517     lv_style_set_text_font(&fonts[FONT_LABEL_LG], &font_lv_demo_high_res_roboto_slab_bold_45);
518     lv_style_set_text_font(&fonts[FONT_LABEL_XL], &font_lv_demo_high_res_roboto_slab_bold_54);
519     lv_style_set_text_font(&fonts[FONT_LABEL_2XL], &font_lv_demo_high_res_roboto_slab_bold_90);
520 }
521 
theme_observer_cb(lv_observer_t * observer,lv_subject_t * subject)522 static void theme_observer_cb(lv_observer_t * observer, lv_subject_t * subject)
523 {
524     const lv_demo_high_res_theme_t * th = lv_subject_get_pointer(subject);
525     const lv_demo_high_res_theme_t * th_other = th == &lv_demo_high_res_theme_light ? &lv_demo_high_res_theme_dark :
526                                                 &lv_demo_high_res_theme_light;
527     lv_demo_high_res_ctx_t * c = lv_observer_get_user_data(observer);
528 
529     for(uint32_t i = 0; i < STYLE_COLOR_COUNT; i++) {
530         lv_color_t color = i == STYLE_COLOR_BASE ? th->base : th->accent;
531         lv_color_t color_inv = i == STYLE_COLOR_ACCENT ? th->accent : th_other->base;
532 
533         lv_style_set_bg_color(&c->styles[i][STYLE_TYPE_OBJ], color);
534         lv_style_set_outline_color(&c->styles[i][STYLE_TYPE_OBJ], color);
535 
536         lv_style_set_text_color(&c->styles[i][STYLE_TYPE_TEXT], color_inv);
537         lv_style_set_line_color(&c->styles[i][STYLE_TYPE_TEXT], color_inv);
538 
539         lv_style_set_image_recolor_opa(&c->styles[i][STYLE_TYPE_A8_IMG], LV_OPA_COVER);
540         lv_style_set_image_recolor(&c->styles[i][STYLE_TYPE_A8_IMG], color_inv);
541     }
542 
543     for(uint32_t i = 0; i < STYLE_COLOR_COUNT; i++) {
544         for(uint32_t j = 0; j < STYLE_TYPE_COUNT; j++) {
545             lv_obj_report_style_change(&c->styles[i][j]);
546         }
547     }
548 }
549 
free_ctx_event_cb(lv_event_t * e)550 static void free_ctx_event_cb(lv_event_t * e)
551 {
552     lv_obj_t * base_obj = lv_event_get_target_obj(e);
553     lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(base_obj);
554 
555     lv_subject_deinit(&c->th);
556 
557     for(uint32_t i = 0; i < IMG_COUNT; i++) {
558         lv_draw_buf_destroy((lv_draw_buf_t *)c->imgs[i]);
559     }
560 
561     for(uint32_t i = 0; i < STYLE_COLOR_COUNT; i++) {
562         for(uint32_t j = 0; j < STYLE_TYPE_COUNT; j++) {
563             lv_style_reset(&c->styles[i][j]);
564         }
565     }
566 
567     for(uint32_t i = 0; i < FONT_COUNT; i++) {
568         lv_style_reset(&c->fonts[i]);
569     }
570 
571     lv_free(c->logo_path);
572     lv_free(c->slides_path);
573 
574     lv_subject_deinit(&c->temperature_units_are_celsius);
575     lv_subject_deinit(&c->ev_charging_progress);
576     lv_subject_deinit(&c->smart_meter_selected_bar);
577 
578     lv_demo_high_res_top_margin_deinit_subjects(c);
579 
580     lv_subject_deinit(&c->subject_groups.time.group);
581     lv_subject_deinit(&c->subject_groups.date.group);
582     lv_subject_deinit(&c->subject_groups.wifi.group);
583 
584     lv_subject_t * subjects = (lv_subject_t *) &c->api.subjects;
585     for(uint32_t i = 0; i < sizeof(c->api.subjects) / sizeof(lv_subject_t); i++) {
586         lv_subject_deinit(&subjects[i]);
587     }
588 
589     uint32_t about_slides_count = lv_array_size(&c->about_slides_array);
590     for(uint32_t i = 0; i < about_slides_count; i++) {
591         lv_image_dsc_t ** slide = lv_array_at(&c->about_slides_array, i);
592         lv_draw_buf_destroy((lv_draw_buf_t *) *slide);
593     }
594     lv_array_deinit(&c->about_slides_array);
595 
596     lv_free(c);
597 
598     lv_obj_set_user_data(base_obj, NULL);
599 }
600 
label_text_temperature_cb(lv_observer_t * observer,lv_subject_t * subject)601 static void label_text_temperature_cb(lv_observer_t * observer, lv_subject_t * subject)
602 {
603     LV_UNUSED(subject);
604     lv_subject_t * temperature_subject = lv_observer_get_user_data(observer);
605     int32_t val = lv_subject_get_int(temperature_subject);
606     lv_obj_t * label = lv_observer_get_target_obj(observer);
607     lv_demo_high_res_ctx_t * c = lv_obj_get_user_data(label);
608 
609     if(!lv_subject_get_int(&c->temperature_units_are_celsius)) {
610         /* convert to fahrenheit */
611         /* + 320 instead of 32 because temperatures in are tenths of a degree */
612         val = val * 9 / 5 + 320;
613     }
614 
615     int32_t full = val / 10;
616     int32_t fraction = val % 10;
617     char buf[16];
618     if(fraction) {
619         lv_snprintf(buf, sizeof(buf), "%"PRId32".%"PRId32"\xc2\xb0", full, fraction);
620     }
621     else {
622         lv_snprintf(buf, sizeof(buf), "%"PRId32"\xc2\xb0", full);
623     }
624 
625     lv_label_set_text(label, buf);
626 }
627 
628 #endif /*LV_USE_DEMO_HIGH_RES*/
629