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