1 /**
2 * @file lv_win.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_win.h"
10 #if LV_USE_WIN != 0
11
12 #include "../lv_misc/lv_debug.h"
13 #include "../lv_themes/lv_theme.h"
14 #include "../lv_core/lv_disp.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19 #define LV_OBJX_NAME "lv_win"
20 #define DEF_TITLE "Window"
21
22 /**********************
23 * TYPEDEFS
24 **********************/
25
26 /** Extended data of win_btn*/
27 typedef struct {
28 /** Ext. of ancestor*/
29 lv_btn_ext_t btn;
30
31 /** Which side of the header should the button be aligned to.
32 * 0: Align to right (default), 1: Align to left */
33 uint8_t alignment_in_header : 1;
34 } lv_win_btn_ext_t;
35
36 enum {
37 LV_WIN_BTN_ALIGN_RIGHT = 0, /**< Align button to right of the header */
38 LV_WIN_BTN_ALIGN_LEFT /**< Align button to left of the header */
39 };
40 typedef uint8_t lv_win_btn_align_t;
41
42 /**********************
43 * STATIC PROTOTYPES
44 **********************/
45 static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param);
46 static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * clip_area, lv_design_mode_t mode);
47 static lv_style_list_t * lv_win_get_style(lv_obj_t * win, uint8_t part);
48 static void lv_win_realign(lv_obj_t * win);
49 static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src);
50 static void lv_win_btn_set_alignment(lv_obj_t * par, const lv_win_btn_align_t alignment);
51 static lv_win_btn_align_t lv_win_btn_get_alignment(const lv_obj_t * par);
52
53 /**********************
54 * STATIC VARIABLES
55 **********************/
56 static lv_design_cb_t ancestor_header_design;
57 static lv_signal_cb_t ancestor_signal;
58
59 /**********************
60 * MACROS
61 **********************/
62
63 /**********************
64 * GLOBAL FUNCTIONS
65 **********************/
66
67 /**
68 * Create a window objects
69 * @param par pointer to an object, it will be the parent of the new window
70 * @param copy pointer to a window object, if not NULL then the new object will be copied from it
71 * @return pointer to the created window
72 */
lv_win_create(lv_obj_t * par,const lv_obj_t * copy)73 lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy)
74 {
75 LV_LOG_TRACE("window create started");
76
77 /*Create the ancestor object*/
78 lv_obj_t * new_win = lv_obj_create(par, copy);
79 LV_ASSERT_MEM(new_win);
80 if(new_win == NULL) return NULL;
81
82 if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_win);
83
84 /*Allocate the object type specific extended data*/
85 lv_win_ext_t * ext = lv_obj_allocate_ext_attr(new_win, sizeof(lv_win_ext_t));
86 LV_ASSERT_MEM(ext);
87 if(ext == NULL) {
88 lv_obj_del(new_win);
89 return NULL;
90 }
91
92 ext->page = NULL;
93 ext->header = NULL;
94 ext->title_txt = lv_mem_alloc(strlen(DEF_TITLE) + 1);
95 strcpy(ext->title_txt, DEF_TITLE);
96
97 /*Init the new window object*/
98 if(copy == NULL) {
99 /* Set a size which fits into the parent.
100 * Don't use `par` directly because if the window is created on a page it is moved to the
101 * scrollable so the parent has changed */
102 lv_coord_t w;
103 lv_coord_t h;
104 if(par) {
105 w = lv_obj_get_width_fit(lv_obj_get_parent(new_win));
106 h = lv_obj_get_height_fit(lv_obj_get_parent(new_win));
107 }
108 else {
109 w = lv_disp_get_hor_res(NULL);
110 h = lv_disp_get_ver_res(NULL);
111 }
112
113 lv_obj_set_size(new_win, w, h);
114
115 ext->btn_w = LV_DPX(65);
116
117 ext->page = lv_page_create(new_win, NULL);
118 lv_obj_add_protect(ext->page, LV_PROTECT_PARENT);
119 lv_page_set_scrollbar_mode(ext->page, LV_SCROLLBAR_MODE_AUTO);
120 lv_obj_clean_style_list(ext->page, LV_PAGE_PART_BG);
121
122 /*Create a holder for the header*/
123 ext->header = lv_obj_create(new_win, NULL);
124 /*Move back to window background because it's automatically moved to the content page*/
125 lv_obj_add_protect(ext->header, LV_PROTECT_PARENT);
126 lv_obj_set_parent(ext->header, new_win);
127 if(ancestor_header_design == NULL) ancestor_header_design = lv_obj_get_design_cb(ext->header);
128 lv_obj_set_height(ext->header, LV_DPX(65));
129
130 lv_obj_set_design_cb(ext->header, lv_win_header_design);
131 lv_obj_set_signal_cb(new_win, lv_win_signal);
132
133 lv_theme_apply(new_win, LV_THEME_WIN);
134 }
135 /*Copy an existing object*/
136 else {
137 lv_win_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
138 /*Create the objects*/
139 ext->header = lv_obj_create(new_win, copy_ext->header);
140 ext->title_txt = lv_mem_alloc(strlen(copy_ext->title_txt) + 1);
141 strcpy(ext->title_txt, copy_ext->title_txt);
142 ext->page = lv_page_create(new_win, copy_ext->page);
143 ext->btn_w = copy_ext->btn_w;
144
145 /*Copy the buttons*/
146 lv_obj_t * child;
147 child = lv_obj_get_child_back(copy_ext->header, NULL);
148 child = lv_obj_get_child_back(copy_ext->header, child); /*Sip the title*/
149 while(child != NULL) {
150 lv_obj_t * btn = lv_btn_create(ext->header, child);
151 lv_img_create(btn, lv_obj_get_child(child, NULL));
152 child = lv_obj_get_child_back(copy_ext->header, child);
153 }
154
155 lv_obj_set_signal_cb(new_win, lv_win_signal);
156 }
157
158 /*Refresh the style with new signal function*/
159 lv_obj_refresh_style(new_win, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
160
161 lv_win_realign(new_win);
162
163 LV_LOG_INFO("window created");
164
165 return new_win;
166 }
167
168 /**
169 * Delete all children of the scrl object, without deleting scrl child.
170 * @param win pointer to an object
171 */
lv_win_clean(lv_obj_t * win)172 void lv_win_clean(lv_obj_t * win)
173 {
174 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
175
176 lv_obj_t * scrl = lv_page_get_scrollable(win);
177 lv_obj_clean(scrl);
178 }
179
180 /*======================
181 * Add/remove functions
182 *=====================*/
183
184 /**
185 * Add control button to the header of the window
186 * @param win pointer to a window object
187 * @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
188 * @param alignment button alignment on the header
189 * @return pointer to the created button object
190 */
lv_win_add_btn_right(lv_obj_t * win,const void * img_src)191 lv_obj_t * lv_win_add_btn_right(lv_obj_t * win, const void * img_src)
192 {
193 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
194 LV_ASSERT_NULL(img_src);
195
196 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
197
198 lv_obj_t * btn = lv_win_btn_create(ext->header, img_src);
199 lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_RIGHT);
200
201 lv_win_realign(win);
202
203 return btn;
204 }
205
206 /**
207 * Add control button on the left side of the window header
208 * @param win pointer to a window object
209 * @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
210 * @return pointer to the created button object
211 */
lv_win_add_btn_left(lv_obj_t * win,const void * img_src)212 lv_obj_t * lv_win_add_btn_left(lv_obj_t * win, const void * img_src)
213 {
214 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
215 LV_ASSERT_NULL(img_src);
216
217 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
218
219 lv_obj_t * btn = lv_win_btn_create(ext->header, img_src);
220 lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_LEFT);
221
222 lv_win_realign(win);
223
224 return btn;
225 }
226
227 /*=====================
228 * Setter functions
229 *====================*/
230
231 /**
232 * Can be assigned to a window control button to close the window
233 * @param btn pointer to the control button on the widows header
234 * @param evet the event type
235 */
lv_win_close_event_cb(lv_obj_t * btn,lv_event_t event)236 void lv_win_close_event_cb(lv_obj_t * btn, lv_event_t event)
237 {
238 LV_ASSERT_OBJ(btn, "lv_btn");
239
240 if(event == LV_EVENT_RELEASED) {
241 lv_obj_t * win = lv_win_get_from_btn(btn);
242
243 lv_obj_del(win);
244 }
245 }
246
247 /**
248 * Set the title of a window
249 * @param win pointer to a window object
250 * @param title string of the new title
251 */
lv_win_set_title(lv_obj_t * win,const char * title)252 void lv_win_set_title(lv_obj_t * win, const char * title)
253 {
254 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
255 LV_ASSERT_STR(title);
256
257 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
258
259 ext->title_txt = lv_mem_realloc(ext->title_txt, strlen(title) + 1);
260 LV_ASSERT_MEM(ext->title_txt);
261 if(ext->title_txt == NULL) return;
262
263 strcpy(ext->title_txt, title);
264 lv_obj_invalidate(ext->header);
265 }
266
267 /**
268 * Set the height of the header
269 * @param win pointer to a window object
270 * @param height height of the header
271 */
lv_win_set_header_height(lv_obj_t * win,lv_coord_t height)272 void lv_win_set_header_height(lv_obj_t * win, lv_coord_t height)
273 {
274 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
275
276 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
277
278 lv_obj_set_height(ext->header, height);
279 lv_win_realign(win);
280 }
281
282 /**
283 * Set the width of the control buttons on the header
284 * @param win pointer to a window object
285 * @param width width of the control button. 0: to make them square automatically.
286 */
lv_win_set_btn_width(lv_obj_t * win,lv_coord_t width)287 void lv_win_set_btn_width(lv_obj_t * win, lv_coord_t width)
288 {
289 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
290
291 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
292 ext->btn_w = width;
293 lv_win_realign(win);
294 }
295
296 /**
297 * Set the size of the content area.
298 * It's the effective area where object can be placed.
299 * @param win pointer to a window object
300 * @param w width
301 * @param h height (the window will be higher with the height of the header)
302 */
lv_win_set_content_size(lv_obj_t * win,lv_coord_t w,lv_coord_t h)303 void lv_win_set_content_size(lv_obj_t * win, lv_coord_t w, lv_coord_t h)
304 {
305 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
306
307 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
308 h += lv_obj_get_height(ext->header);
309
310 lv_obj_set_size(win, w, h);
311 }
312
313 /**
314 * Set the layout of the window
315 * @param win pointer to a window object
316 * @param layout the layout from 'lv_layout_t'
317 */
lv_win_set_layout(lv_obj_t * win,lv_layout_t layout)318 void lv_win_set_layout(lv_obj_t * win, lv_layout_t layout)
319 {
320 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
321
322 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
323 lv_page_set_scrl_layout(ext->page, layout);
324 }
325
326 /**
327 * Set the scroll bar mode of a window
328 * @param win pointer to a window object
329 * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t'
330 */
lv_win_set_scrollbar_mode(lv_obj_t * win,lv_scrollbar_mode_t sb_mode)331 void lv_win_set_scrollbar_mode(lv_obj_t * win, lv_scrollbar_mode_t sb_mode)
332 {
333 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
334
335 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
336 lv_page_set_scrollbar_mode(ext->page, sb_mode);
337 }
338 /**
339 * Set focus animation duration on `lv_win_focus()`
340 * @param win pointer to a window object
341 * @param anim_time duration of animation [ms]
342 */
lv_win_set_anim_time(lv_obj_t * win,uint16_t anim_time)343 void lv_win_set_anim_time(lv_obj_t * win, uint16_t anim_time)
344 {
345 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
346
347 lv_page_set_anim_time(lv_win_get_content(win), anim_time);
348 }
349
350 /**
351 * Set drag status of a window. If set to 'true' window can be dragged like on a PC.
352 * @param win pointer to a window object
353 * @param en whether dragging is enabled
354 */
lv_win_set_drag(lv_obj_t * win,bool en)355 void lv_win_set_drag(lv_obj_t * win, bool en)
356 {
357 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
358
359 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
360 lv_obj_t * win_header = ext->header;
361 lv_obj_set_drag_parent(win_header, en);
362 lv_obj_set_drag(win, en);
363 }
364
365 /*=====================
366 * Getter functions
367 *====================*/
368
369 /**
370 * Get the title of a window
371 * @param win pointer to a window object
372 * @return title string of the window
373 */
lv_win_get_title(const lv_obj_t * win)374 const char * lv_win_get_title(const lv_obj_t * win)
375 {
376 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
377
378 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
379 return ext->title_txt;
380 }
381
382 /**
383 * Get the content holder object of window (`lv_page`) to allow additional customization
384 * @param win pointer to a window object
385 * @return the Page object where the window's content is
386 */
lv_win_get_content(const lv_obj_t * win)387 lv_obj_t * lv_win_get_content(const lv_obj_t * win)
388 {
389 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
390
391 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
392 return ext->page;
393 }
394
395 /**
396 * Get the header height
397 * @param win pointer to a window object
398 * @return header height
399 */
lv_win_get_header_height(const lv_obj_t * win)400 lv_coord_t lv_win_get_header_height(const lv_obj_t * win)
401 {
402 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
403
404 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
405 return lv_obj_get_height(ext->header);
406 }
407
408 /**
409 * Get the width of the control buttons on the header
410 * @param win pointer to a window object
411 * @return width of the control button. 0: square.
412 */
lv_win_get_btn_width(lv_obj_t * win)413 lv_coord_t lv_win_get_btn_width(lv_obj_t * win)
414 {
415 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
416
417 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
418 return ext->btn_w;
419
420 }
421
422 /**
423 * Get the pointer of a widow from one of its control button.
424 * It is useful in the action of the control buttons where only button is known.
425 * @param ctrl_btn pointer to a control button of a window
426 * @return pointer to the window of 'ctrl_btn'
427 */
lv_win_get_from_btn(const lv_obj_t * ctrl_btn)428 lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn)
429 {
430 LV_ASSERT_OBJ(ctrl_btn, "lv_btn");
431
432 lv_obj_t * header = lv_obj_get_parent(ctrl_btn);
433 lv_obj_t * win = lv_obj_get_parent(header);
434
435 return win;
436 }
437
438 /**
439 * Get the layout of a window
440 * @param win pointer to a window object
441 * @return the layout of the window (from 'lv_layout_t')
442 */
lv_win_get_layout(lv_obj_t * win)443 lv_layout_t lv_win_get_layout(lv_obj_t * win)
444 {
445 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
446
447 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
448 return lv_page_get_scrl_layout(ext->page);
449 }
450
451 /**
452 * Get the scroll bar mode of a window
453 * @param win pointer to a window object
454 * @return the scroll bar mode of the window (from 'lv_sb_mode_t')
455 */
lv_win_get_sb_mode(lv_obj_t * win)456 lv_scrollbar_mode_t lv_win_get_sb_mode(lv_obj_t * win)
457 {
458 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
459
460 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
461 return lv_page_get_scrollbar_mode(ext->page);
462 }
463
464 /**
465 * Get focus animation duration
466 * @param win pointer to a window object
467 * @return duration of animation [ms]
468 */
lv_win_get_anim_time(const lv_obj_t * win)469 uint16_t lv_win_get_anim_time(const lv_obj_t * win)
470 {
471 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
472
473 return lv_page_get_anim_time(lv_win_get_content(win));
474 }
475
476 /**
477 * Get width of the content area (page scrollable) of the window
478 * @param win pointer to a window object
479 * @return the width of the content_bg area
480 */
lv_win_get_width(lv_obj_t * win)481 lv_coord_t lv_win_get_width(lv_obj_t * win)
482 {
483 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
484
485 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
486 lv_obj_t * scrl = lv_page_get_scrollable(ext->page);
487 lv_coord_t left = lv_obj_get_style_pad_left(win, LV_WIN_PART_BG);
488 lv_coord_t right = lv_obj_get_style_pad_left(win, LV_WIN_PART_BG);
489
490 return lv_obj_get_width_fit(scrl) - left - right;
491 }
492
493 /*=====================
494 * Other functions
495 *====================*/
496
497 /**
498 * Focus on an object. It ensures that the object will be visible in the window.
499 * @param win pointer to a window object
500 * @param obj pointer to an object to focus (must be in the window)
501 * @param anim_en LV_ANIM_ON focus with an animation; LV_ANIM_OFF focus without animation
502 */
lv_win_focus(lv_obj_t * win,lv_obj_t * obj,lv_anim_enable_t anim_en)503 void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, lv_anim_enable_t anim_en)
504 {
505 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
506 LV_ASSERT_OBJ(obj, "");
507
508
509 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
510 lv_page_focus(ext->page, obj, anim_en);
511 }
512
513 /**********************
514 * STATIC FUNCTIONS
515 **********************/
516 /**
517 * Handle the drawing related tasks of the window header
518 * @param header pointer to an object
519 * @param clip_area the object will be drawn only in this area
520 * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
521 * (return 'true' if yes)
522 * LV_DESIGN_DRAW: draw the object (always return 'true')
523 * LV_DESIGN_DRAW_POST: drawing after every children are drawn
524 * @param return an element of `lv_design_res_t`
525 */
lv_win_header_design(lv_obj_t * header,const lv_area_t * clip_area,lv_design_mode_t mode)526 static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * clip_area, lv_design_mode_t mode)
527 {
528 /*Return false if the object is not covers the mask_p area*/
529 if(mode == LV_DESIGN_COVER_CHK) {
530 return ancestor_header_design(header, clip_area, mode);
531 }
532 /*Draw the object*/
533 else if(mode == LV_DESIGN_DRAW_MAIN) {
534 ancestor_header_design(header, clip_area, mode);
535
536 lv_obj_t * win = lv_obj_get_parent(header);
537 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
538
539 lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER);
540 lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER);
541
542 lv_draw_label_dsc_t label_dsc;
543 lv_draw_label_dsc_init(&label_dsc);
544 lv_obj_init_draw_label_dsc(header, LV_OBJ_PART_MAIN, &label_dsc);
545
546 lv_area_t txt_area;
547 lv_point_t txt_size;
548
549 _lv_txt_get_size(&txt_size, ext->title_txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX,
550 label_dsc.flag);
551
552 lv_obj_t * btn = NULL;
553
554 lv_coord_t btn_h = lv_obj_get_height_fit(header);
555 lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h;
556
557 /*Get x position of the title (should be on the right of the buttons on the left)*/
558
559 lv_coord_t left_btn_offset = 0;
560 btn = lv_obj_get_child_back(ext->header, NULL);
561 while(btn != NULL) {
562 if(LV_WIN_BTN_ALIGN_LEFT == lv_win_btn_get_alignment(btn)) {
563 left_btn_offset += btn_w + header_inner;
564 }
565
566 btn = lv_obj_get_child_back(header, btn);
567 }
568
569 txt_area.x1 = header->coords.x1 + header_left + left_btn_offset;
570 txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2;
571 txt_area.x2 = txt_area.x1 + txt_size.x + left_btn_offset;
572 txt_area.y2 = txt_area.y1 + txt_size.y;
573
574 lv_draw_label(&txt_area, clip_area, &label_dsc, ext->title_txt, NULL);
575 }
576 else if(mode == LV_DESIGN_DRAW_POST) {
577 ancestor_header_design(header, clip_area, mode);
578 }
579
580 return LV_DESIGN_RES_OK;
581 }
582 /**
583 * Signal function of the window
584 * @param win pointer to a window object
585 * @param sign a signal type from lv_signal_t enum
586 * @param param pointer to a signal specific variable
587 * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
588 */
lv_win_signal(lv_obj_t * win,lv_signal_t sign,void * param)589 static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param)
590 {
591 lv_res_t res;
592
593 if(sign == LV_SIGNAL_GET_STYLE) {
594 lv_get_style_info_t * info = param;
595 info->result = lv_win_get_style(win, info->part);
596 if(info->result != NULL) return LV_RES_OK;
597 else return ancestor_signal(win, sign, param);
598 }
599 else if(sign == LV_SIGNAL_GET_STATE_DSC) {
600 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
601 lv_get_state_info_t * info = param;
602 if(info->part == LV_WIN_PART_CONTENT_SCROLLABLE) info->result = lv_obj_get_state(lv_page_get_scrollable(ext->page),
603 LV_CONT_PART_MAIN);
604 else if(info->part == LV_WIN_PART_SCROLLBAR) info->result = lv_obj_get_state(ext->page, LV_PAGE_PART_SCROLLBAR);
605 else if(info->part == LV_WIN_PART_HEADER) info->result = lv_obj_get_state(ext->header, LV_OBJ_PART_MAIN);
606 return LV_RES_OK;
607 }
608
609 /* Include the ancient signal function */
610 res = ancestor_signal(win, sign, param);
611 if(res != LV_RES_OK) return res;
612 if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
613
614 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
615 if(sign == LV_SIGNAL_CHILD_CHG) { /*Move children to the page*/
616 lv_obj_t * page = ext->page;
617 if(page != NULL) {
618 lv_obj_t * child;
619 child = lv_obj_get_child(win, NULL);
620 while(child != NULL) {
621 if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) {
622 lv_obj_t * tmp = child;
623 child = lv_obj_get_child(win, child); /*Get the next child before move this*/
624 lv_obj_set_parent(tmp, page);
625 }
626 else {
627 child = lv_obj_get_child(win, child);
628 }
629 }
630 }
631 }
632 else if(sign == LV_SIGNAL_STYLE_CHG) {
633 lv_win_realign(win);
634 }
635 else if(sign == LV_SIGNAL_COORD_CHG) {
636 /*If the size is changed refresh the window*/
637 if(lv_area_get_width(param) != lv_obj_get_width(win) || lv_area_get_height(param) != lv_obj_get_height(win)) {
638 lv_win_realign(win);
639 }
640 }
641 else if(sign == LV_SIGNAL_CLEANUP) {
642 ext->header = NULL; /*These objects were children so they are already invalid*/
643 ext->page = NULL;
644 lv_mem_free(ext->title_txt);
645 ext->title_txt = NULL;
646 }
647 else if(sign == LV_SIGNAL_CONTROL) {
648 #if LV_USE_GROUP
649 /*Forward all the control signals to the page*/
650 ext->page->signal_cb(ext->page, sign, param);
651 #endif
652 }
653
654 return res;
655 }
656 /**
657 * Get the style descriptor of a part of the object
658 * @param win pointer the object
659 * @param part the part of the win. (LV_PAGE_WIN_...)
660 * @return pointer to the style descriptor of the specified part
661 */
lv_win_get_style(lv_obj_t * win,uint8_t part)662 static lv_style_list_t * lv_win_get_style(lv_obj_t * win, uint8_t part)
663 {
664 LV_ASSERT_OBJ(win, LV_OBJX_NAME);
665
666 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
667 lv_style_list_t * style_dsc_p;
668
669 switch(part) {
670 case LV_WIN_PART_BG:
671 style_dsc_p = &win->style_list;
672 break;
673 case LV_WIN_PART_HEADER:
674 style_dsc_p = lv_obj_get_style_list(ext->header, LV_OBJ_PART_MAIN);
675 break;
676 case LV_WIN_PART_SCROLLBAR:
677 style_dsc_p = lv_obj_get_style_list(ext->page, LV_PAGE_PART_SCROLLBAR);
678 break;
679 case LV_WIN_PART_CONTENT_SCROLLABLE:
680 style_dsc_p = lv_obj_get_style_list(ext->page, LV_PAGE_PART_SCROLLABLE);
681 break;
682 default:
683 style_dsc_p = NULL;
684 }
685
686 return style_dsc_p;
687 }
688 /**
689 * Realign the building elements of a window
690 * @param win pointer to a window object
691 */
lv_win_realign(lv_obj_t * win)692 static void lv_win_realign(lv_obj_t * win)
693 {
694 lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
695
696 if(ext->page == NULL || ext->header == NULL) return;
697
698 lv_obj_set_width(ext->header, lv_obj_get_width(win));
699
700 lv_obj_t * btn;
701 lv_obj_t * btn_prev_at_left = NULL;
702 lv_obj_t * btn_prev_at_right = NULL;
703
704 bool is_header_right_side_empty = true;
705 bool is_header_left_side_empty = true;
706
707 lv_coord_t btn_h = lv_obj_get_height_fit(ext->header);
708 lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h;
709 lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER);
710 lv_style_int_t header_right = lv_obj_get_style_pad_right(win, LV_WIN_PART_HEADER);
711 lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER);
712
713 /*Refresh the size of all control buttons*/
714 btn = lv_obj_get_child_back(ext->header, NULL);
715 while(btn != NULL) {
716 lv_obj_set_size(btn, btn_w, btn_h);
717 uint8_t btn_alignment = lv_win_btn_get_alignment(btn);
718
719 if(LV_WIN_BTN_ALIGN_RIGHT == btn_alignment) {
720 if(is_header_right_side_empty) {
721 /* Align the button to the right of the header */
722 lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, -header_right, 0);
723
724 is_header_right_side_empty = false;
725 }
726 else {
727 /* Align the button to the left of the previous button */
728 lv_obj_align(btn, btn_prev_at_right, LV_ALIGN_OUT_LEFT_MID, -header_inner, 0);
729 }
730
731 btn_prev_at_right = btn;
732 }
733 else if(LV_WIN_BTN_ALIGN_LEFT == btn_alignment) {
734 if(is_header_left_side_empty) {
735 /* Align the button to the right of the header */
736 lv_obj_align(btn, ext->header, LV_ALIGN_IN_LEFT_MID, header_left, 0);
737
738 is_header_left_side_empty = false;
739 }
740 else {
741 /* Align the button to the right of the previous button */
742 lv_obj_align(btn, btn_prev_at_left, LV_ALIGN_OUT_RIGHT_MID, header_inner, 0);
743 }
744
745 btn_prev_at_left = btn;
746 }
747
748 btn = lv_obj_get_child_back(ext->header, btn);
749 }
750
751 lv_obj_set_pos(ext->header, 0, 0);
752
753 lv_obj_set_size(ext->page, lv_obj_get_width(win), lv_obj_get_height(win) - lv_obj_get_height(ext->header));
754 lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
755 }
756
lv_win_btn_create(lv_obj_t * par,const void * img_src)757 static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src)
758 {
759 LV_LOG_TRACE("win btn create started");
760
761 lv_obj_t * win_btn;
762
763 win_btn = lv_btn_create(par, NULL);
764 LV_ASSERT_MEM(win_btn);
765 if(win_btn == NULL) return NULL;
766
767 /*Allocate the extended data*/
768 lv_win_btn_ext_t * ext = lv_obj_allocate_ext_attr(win_btn, sizeof(lv_win_btn_ext_t));
769 LV_ASSERT_MEM(ext);
770 if(ext == NULL) {
771 lv_obj_del(win_btn);
772 return NULL;
773 }
774
775 ext->alignment_in_header = LV_WIN_BTN_ALIGN_RIGHT;
776
777 lv_obj_set_click(win_btn, true);
778 lv_win_btn_set_alignment(win_btn, LV_WIN_BTN_ALIGN_RIGHT);
779
780 lv_theme_apply(win_btn, LV_THEME_WIN_BTN);
781 lv_coord_t btn_size = lv_obj_get_height_fit(par);
782 lv_obj_set_size(win_btn, btn_size, btn_size);
783
784 lv_obj_t * img = lv_img_create(win_btn, NULL);
785 lv_obj_set_click(img, false);
786 lv_img_set_src(img, img_src);
787
788 LV_LOG_INFO("win btn created");
789
790 return win_btn;
791 }
792
lv_win_btn_set_alignment(lv_obj_t * win_btn,const uint8_t alignment)793 static void lv_win_btn_set_alignment(lv_obj_t * win_btn, const uint8_t alignment)
794 {
795 lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn);
796
797 ext->alignment_in_header = alignment;
798 }
799
lv_win_btn_get_alignment(const lv_obj_t * win_btn)800 static uint8_t lv_win_btn_get_alignment(const lv_obj_t * win_btn)
801 {
802 lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn);
803
804 return ext->alignment_in_header;
805 }
806
807 #endif
808