1 /**
2  * @file lv_demo_smartwatch_easter_egg.c
3  * Easter Egg screen - LVGL animated logo.
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_demo_smartwatch.h"
10 #if LV_USE_DEMO_SMARTWATCH
11 
12 #include "lv_demo_smartwatch_private.h"
13 #include "lv_demo_smartwatch_easter_egg.h"
14 #include "../../lvgl_private.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 
20 /**********************
21  *      TYPEDEFS
22  **********************/
23 
24 /**********************
25  *  STATIC PROTOTYPES
26  **********************/
27 static void create_screen_easter_egg(void);
28 static void create_screen_event_cb(lv_event_t * e);
29 
30 static void get_random_position(lv_coord_t * x, lv_coord_t * y, uint64_t * a);
31 static void set_obj_pos_angle(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, uint64_t a);
32 static void animate_drift(lv_obj_t * img);
33 static void animate_back_to_center(lv_obj_t * img, uint32_t delay);
34 static void drift_timer_cb(lv_timer_t * timer);
35 static void start_drift_animation(void);
36 static void stop_drift_animation(void);
37 
38 /**********************
39  *  STATIC VARIABLES
40  **********************/
41 
42 static lv_obj_t * easter_egg_screen;
43 static lv_obj_t * lvgl_logo_black;
44 static lv_obj_t * lvgl_logo_blue;
45 static lv_obj_t * lvgl_logo_green;
46 static lv_obj_t * lvgl_logo_red;
47 
48 static lv_timer_t * drift_timer_black = NULL; /* Timer for the black logo */
49 static lv_timer_t * drift_timer_blue = NULL; /* Timer for the blue logo */
50 static lv_timer_t * drift_timer_green = NULL; /* Timer for the green logo */
51 static lv_timer_t * drift_timer_red = NULL;  /* Timer for the red logo */
52 
53 /**********************
54  *      MACROS
55  **********************/
56 
57 /**********************
58  *   GLOBAL FUNCTIONS
59  **********************/
60 
lv_demo_smartwatch_easter_egg_create(void)61 void lv_demo_smartwatch_easter_egg_create(void)
62 {
63     create_screen_easter_egg();
64 }
65 
lv_demo_smartwatch_easter_egg_load(lv_screen_load_anim_t anim_type,uint32_t time,uint32_t delay)66 void lv_demo_smartwatch_easter_egg_load(lv_screen_load_anim_t anim_type, uint32_t time, uint32_t delay)
67 {
68 
69     /* set positions and angle on load */
70     set_obj_pos_angle(lvgl_logo_black, -88, 88, 2700);
71     set_obj_pos_angle(lvgl_logo_blue, -88, -88, 2700);
72     set_obj_pos_angle(lvgl_logo_green, 88, 88, 2700);
73     set_obj_pos_angle(lvgl_logo_red, 88, -88, 2700);
74 
75     /* Return all images to the center with an animation */
76     animate_back_to_center(lvgl_logo_black, 1000);
77     animate_back_to_center(lvgl_logo_blue, 1000);
78     animate_back_to_center(lvgl_logo_green, 1000);
79     animate_back_to_center(lvgl_logo_red, 1000);
80 
81     lv_screen_load_anim(easter_egg_screen, anim_type, time, delay, false);
82 }
83 
84 /**********************
85  *   STATIC FUNCTIONS
86  **********************/
87 
88 /**
89  * Function to generate random target positions within the screen, keeping the images visible
90  * @param x random x coordinate to be returned
91  * @param y random y coordinate to be returned
92  * @param a random rotation angle to be returned
93  */
get_random_position(lv_coord_t * x,lv_coord_t * y,uint64_t * a)94 static void get_random_position(lv_coord_t * x, lv_coord_t * y, uint64_t * a)
95 {
96     *x = lv_rand(-88, 88);
97     *y = lv_rand(-88, 88);
98     *a = lv_rand(0, 3600); /* Random rotation between (0 and 360 degrees) * 10 */
99 }
100 
101 
set_obj_pos_angle(lv_obj_t * obj,lv_coord_t x,lv_coord_t y,uint64_t a)102 static void set_obj_pos_angle(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, uint64_t a)
103 {
104     if(obj == NULL) {
105         LV_LOG_WARN("set_obj_pos_angle() object is null");
106         return;
107     }
108     lv_obj_set_x(obj, x);
109     lv_obj_set_y(obj, y);
110     lv_image_set_rotation(obj, a);
111 }
112 
113 /**
114  * Animation callback to move images to a new random position
115  * @param img the image object to animate
116  */
animate_drift(lv_obj_t * img)117 static void animate_drift(lv_obj_t * img)
118 {
119     lv_coord_t x_target;
120     lv_coord_t y_target;
121     uint64_t a_target;
122     get_random_position(&x_target, &y_target, &a_target);
123 
124     lv_anim_t anim_x;
125     lv_anim_init(&anim_x);
126     lv_anim_set_var(&anim_x, img);
127     lv_anim_set_values(&anim_x, lv_obj_get_x_aligned(img), x_target);
128     lv_anim_set_duration(&anim_x, 3000);
129     lv_anim_set_exec_cb(&anim_x, (lv_anim_exec_xcb_t)lv_obj_set_x);
130     lv_anim_start(&anim_x);
131 
132     lv_anim_t anim_y;
133     lv_anim_init(&anim_y);
134     lv_anim_set_var(&anim_y, img);
135     lv_anim_set_values(&anim_y, lv_obj_get_y_aligned(img), y_target);
136     lv_anim_set_duration(&anim_y, 3000);
137     lv_anim_set_exec_cb(&anim_y, (lv_anim_exec_xcb_t)lv_obj_set_y);
138     lv_anim_start(&anim_y);
139 
140     lv_anim_t anim_a;
141     lv_anim_init(&anim_a);
142     lv_anim_set_var(&anim_a, img);
143     lv_anim_set_values(&anim_a, lv_image_get_rotation(img), a_target);
144     lv_anim_set_duration(&anim_a, 3000);
145     lv_anim_set_exec_cb(&anim_a, (lv_anim_exec_xcb_t)lv_image_set_rotation);
146     lv_anim_start(&anim_a);
147 }
148 
149 /**
150  * Function to gradually drift images back to the center (0, 0) when touched
151  * @param img the image object to animate
152  */
animate_back_to_center(lv_obj_t * img,uint32_t delay)153 static void animate_back_to_center(lv_obj_t * img, uint32_t delay)
154 {
155     lv_anim_t anim_x;
156     lv_anim_init(&anim_x);
157     lv_anim_set_var(&anim_x, img);
158     lv_anim_set_values(&anim_x, lv_obj_get_x_aligned(img), 0);
159     lv_anim_set_duration(&anim_x, 1000);
160     lv_anim_set_delay(&anim_x, delay);
161     lv_anim_set_exec_cb(&anim_x, (lv_anim_exec_xcb_t)lv_obj_set_x);
162     lv_anim_start(&anim_x);
163 
164     lv_anim_t anim_y;
165     lv_anim_init(&anim_y);
166     lv_anim_set_var(&anim_y, img);
167     lv_anim_set_values(&anim_y, lv_obj_get_y_aligned(img), 0);
168     lv_anim_set_duration(&anim_y, 1000);
169     lv_anim_set_delay(&anim_y, delay);
170     lv_anim_set_exec_cb(&anim_y, (lv_anim_exec_xcb_t)lv_obj_set_y);
171     lv_anim_start(&anim_y);
172 
173     lv_anim_t anim_a;
174     lv_anim_init(&anim_a);
175     lv_anim_set_var(&anim_a, img);
176     lv_anim_set_values(&anim_a, lv_image_get_rotation(img), 0);
177     lv_anim_set_duration(&anim_a, 1000);
178     lv_anim_set_delay(&anim_a, delay);
179     lv_anim_set_exec_cb(&anim_a, (lv_anim_exec_xcb_t)lv_image_set_rotation);
180     lv_anim_start(&anim_a);
181 }
182 
183 /**
184  * Timer callback for continuous drift
185  */
drift_timer_cb(lv_timer_t * timer)186 static void drift_timer_cb(lv_timer_t * timer)
187 {
188     lv_obj_t * img = timer->user_data;
189     animate_drift(img);
190 }
191 
192 /**
193  * Start drift animations on screen load
194  */
start_drift_animation(void)195 static void start_drift_animation(void)
196 {
197     /* Create a timer for each image to trigger the drift animation repeatedly */
198     drift_timer_black = lv_timer_create(drift_timer_cb, 3000, lvgl_logo_black);
199     lv_timer_set_repeat_count(drift_timer_black, -1);
200 
201     drift_timer_blue = lv_timer_create(drift_timer_cb, 3000, lvgl_logo_blue);
202     lv_timer_set_repeat_count(drift_timer_blue, -1);
203 
204     drift_timer_green = lv_timer_create(drift_timer_cb, 3000, lvgl_logo_green);
205     lv_timer_set_repeat_count(drift_timer_green, -1);
206 
207     drift_timer_red = lv_timer_create(drift_timer_cb, 3000, lvgl_logo_red);
208     lv_timer_set_repeat_count(drift_timer_red, -1);
209 }
210 
211 /**
212  * Stop animations on screen unload
213  */
stop_drift_animation(void)214 static void stop_drift_animation(void)
215 {
216     /* Stop and delete each timer individually */
217     if(drift_timer_black != NULL) {
218         lv_timer_delete(drift_timer_black);
219         drift_timer_black = NULL;
220     }
221 
222     if(drift_timer_blue != NULL) {
223         lv_timer_delete(drift_timer_blue);
224         drift_timer_blue = NULL;
225     }
226 
227     if(drift_timer_green != NULL) {
228         lv_timer_delete(drift_timer_green);
229         drift_timer_green = NULL;
230     }
231 
232     if(drift_timer_red != NULL) {
233         lv_timer_delete(drift_timer_red);
234         drift_timer_red = NULL;
235     }
236 }
237 
create_screen_easter_egg(void)238 static void create_screen_easter_egg(void)
239 {
240 
241     easter_egg_screen = lv_obj_create(NULL);
242     lv_obj_remove_flag(easter_egg_screen, LV_OBJ_FLAG_SCROLLABLE);
243     lv_obj_set_style_bg_color(easter_egg_screen, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
244     lv_obj_set_style_bg_opa(easter_egg_screen, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
245 
246     lvgl_logo_black = lv_image_create(easter_egg_screen);
247     lv_image_set_src(lvgl_logo_black, &img_lvgl_logo_black_icon);
248     lv_obj_set_width(lvgl_logo_black, LV_SIZE_CONTENT);
249     lv_obj_set_height(lvgl_logo_black, LV_SIZE_CONTENT);
250     lv_obj_set_align(lvgl_logo_black, LV_ALIGN_CENTER);
251     lv_obj_remove_flag(lvgl_logo_black, LV_OBJ_FLAG_SCROLLABLE);
252 
253     lvgl_logo_blue = lv_image_create(easter_egg_screen);
254     lv_image_set_src(lvgl_logo_blue, &img_lvgl_logo_blue_icon);
255     lv_obj_set_width(lvgl_logo_blue, LV_SIZE_CONTENT);
256     lv_obj_set_height(lvgl_logo_blue, LV_SIZE_CONTENT);
257     lv_obj_set_align(lvgl_logo_blue, LV_ALIGN_CENTER);
258     lv_obj_remove_flag(lvgl_logo_blue, LV_OBJ_FLAG_SCROLLABLE);
259 
260     lvgl_logo_red = lv_image_create(easter_egg_screen);
261     lv_image_set_src(lvgl_logo_red, &img_lvgl_logo_red_icon);
262     lv_obj_set_width(lvgl_logo_red, LV_SIZE_CONTENT);
263     lv_obj_set_height(lvgl_logo_red, LV_SIZE_CONTENT);
264     lv_obj_set_align(lvgl_logo_red, LV_ALIGN_CENTER);
265     lv_obj_remove_flag(lvgl_logo_red, LV_OBJ_FLAG_SCROLLABLE);
266 
267     lvgl_logo_green = lv_image_create(easter_egg_screen);
268     lv_image_set_src(lvgl_logo_green, &img_lvgl_logo_green_icon);
269     lv_obj_set_width(lvgl_logo_green, LV_SIZE_CONTENT);
270     lv_obj_set_height(lvgl_logo_green, LV_SIZE_CONTENT);
271     lv_obj_set_align(lvgl_logo_green, LV_ALIGN_CENTER);
272     lv_obj_remove_flag(lvgl_logo_green, LV_OBJ_FLAG_SCROLLABLE);
273 
274     lv_obj_add_event_cb(easter_egg_screen, create_screen_event_cb, LV_EVENT_ALL, NULL);
275 }
276 
create_screen_event_cb(lv_event_t * e)277 static void create_screen_event_cb(lv_event_t * e)
278 {
279     lv_obj_t * active_screen = lv_screen_active();
280     if(active_screen != easter_egg_screen) {
281         /* event was triggered but the current screen is no longer active */
282         return;
283     }
284 
285     lv_event_code_t event_code = lv_event_get_code(e);
286 
287     if(event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_active()) == LV_DIR_RIGHT) {
288         lv_demo_smartwatch_settings_load(LV_SCR_LOAD_ANIM_FADE_OUT, 500, 0);
289         return;
290     }
291     if(event_code == LV_EVENT_SCREEN_LOAD_START) {
292 
293     }
294     if(event_code == LV_EVENT_SCREEN_LOADED) {
295         start_drift_animation();
296     }
297     if(event_code == LV_EVENT_SCREEN_UNLOAD_START) {
298         stop_drift_animation();
299 
300         animate_back_to_center(lvgl_logo_black, 0);
301         animate_back_to_center(lvgl_logo_blue, 0);
302         animate_back_to_center(lvgl_logo_green, 0);
303         animate_back_to_center(lvgl_logo_red, 0);
304 
305     }
306 
307     if(event_code == LV_EVENT_PRESSED) {
308         stop_drift_animation();
309 
310         /* Return all images to the center */
311         animate_back_to_center(lvgl_logo_black, 0);
312         animate_back_to_center(lvgl_logo_blue, 0);
313         animate_back_to_center(lvgl_logo_green, 0);
314         animate_back_to_center(lvgl_logo_red, 0);
315     }
316     else if(event_code == LV_EVENT_RELEASED) {
317         start_drift_animation();
318     }
319 }
320 
321 #endif /*LV_USE_DEMO_SMARTWATCH*/
322