1 /**
2  * @file lv_msgbox.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_msgbox.h"
10 #if LV_USE_MSGBOX
11 
12 #include "../../../misc/lv_assert.h"
13 
14 /*********************
15  *      DEFINES
16  *********************/
17 #define LV_MSGBOX_FLAG_AUTO_PARENT  LV_OBJ_FLAG_WIDGET_1        /*Mark that the parent was automatically created*/
18 #define MY_CLASS    &lv_msgbox_class
19 
20 /**********************
21  *      TYPEDEFS
22  **********************/
23 
24 /**********************
25  *  STATIC PROTOTYPES
26  **********************/
27 static void msgbox_close_click_event_cb(lv_event_t * e);
28 
29 /**********************
30  *  STATIC VARIABLES
31  **********************/
32 const lv_obj_class_t lv_msgbox_class = {
33     .base_class = &lv_obj_class,
34     .width_def = LV_DPI_DEF * 2,
35     .height_def = LV_SIZE_CONTENT,
36     .instance_size = sizeof(lv_msgbox_t)
37 };
38 
39 const lv_obj_class_t lv_msgbox_content_class = {
40     .base_class = &lv_obj_class,
41     .width_def = LV_PCT(100),
42     .height_def = LV_SIZE_CONTENT,
43     .instance_size = sizeof(lv_obj_t)
44 };
45 
46 const lv_obj_class_t lv_msgbox_backdrop_class = {
47     .base_class = &lv_obj_class,
48     .width_def = LV_PCT(100),
49     .height_def = LV_PCT(100),
50     .instance_size = sizeof(lv_obj_t)
51 };
52 
53 /**********************
54  *      MACROS
55  **********************/
56 
57 /**********************
58  *   GLOBAL FUNCTIONS
59  **********************/
60 
lv_msgbox_create(lv_obj_t * parent,const char * title,const char * txt,const char * btn_txts[],bool add_close_btn)61 lv_obj_t * lv_msgbox_create(lv_obj_t * parent, const char * title, const char * txt, const char * btn_txts[],
62                             bool add_close_btn)
63 {
64     LV_LOG_INFO("begin");
65     bool auto_parent = false;
66     if(parent == NULL) {
67         auto_parent = true;
68         parent = lv_obj_class_create_obj(&lv_msgbox_backdrop_class, lv_layer_top());
69         LV_ASSERT_MALLOC(parent);
70         lv_obj_class_init_obj(parent);
71         lv_obj_clear_flag(parent, LV_OBJ_FLAG_IGNORE_LAYOUT);
72         lv_obj_set_size(parent, LV_PCT(100), LV_PCT(100));
73     }
74 
75     lv_obj_t * obj = lv_obj_class_create_obj(&lv_msgbox_class, parent);
76     LV_ASSERT_MALLOC(obj);
77     if(obj == NULL) return NULL;
78     lv_obj_class_init_obj(obj);
79     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
80 
81     if(auto_parent) lv_obj_add_flag(obj, LV_MSGBOX_FLAG_AUTO_PARENT);
82 
83     lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_WRAP);
84 
85     bool has_title = title && strlen(title) > 0;
86 
87     /*When a close button is required, we need the empty label as spacer to push the button to the right*/
88     if(add_close_btn || has_title) {
89         mbox->title = lv_label_create(obj);
90         lv_label_set_text(mbox->title, has_title ? title : "");
91         lv_label_set_long_mode(mbox->title, LV_LABEL_LONG_SCROLL_CIRCULAR);
92         if(add_close_btn) lv_obj_set_flex_grow(mbox->title, 1);
93         else lv_obj_set_width(mbox->title, LV_PCT(100));
94     }
95 
96     if(add_close_btn) {
97         mbox->close_btn = lv_btn_create(obj);
98         lv_obj_set_ext_click_area(mbox->close_btn, LV_DPX(10));
99         lv_obj_add_event_cb(mbox->close_btn, msgbox_close_click_event_cb, LV_EVENT_CLICKED, NULL);
100         lv_obj_t * label = lv_label_create(mbox->close_btn);
101         lv_label_set_text(label, LV_SYMBOL_CLOSE);
102         const lv_font_t * font = lv_obj_get_style_text_font(mbox->close_btn, LV_PART_MAIN);
103         lv_coord_t close_btn_size = lv_font_get_line_height(font) + LV_DPX(10);
104         lv_obj_set_size(mbox->close_btn, close_btn_size, close_btn_size);
105         lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
106     }
107 
108     mbox->content = lv_obj_class_create_obj(&lv_msgbox_content_class, obj);
109     LV_ASSERT_MALLOC(mbox->content);
110     if(mbox->content == NULL) return NULL;
111     lv_obj_class_init_obj(mbox->content);
112 
113     bool has_txt = txt && strlen(txt) > 0;
114     if(has_txt) {
115         mbox->text = lv_label_create(mbox->content);
116         lv_label_set_text(mbox->text, txt);
117         lv_label_set_long_mode(mbox->text, LV_LABEL_LONG_WRAP);
118         lv_obj_set_width(mbox->text, lv_pct(100));
119     }
120 
121     if(btn_txts) {
122         mbox->btns = lv_btnmatrix_create(obj);
123         lv_btnmatrix_set_map(mbox->btns, btn_txts);
124         lv_btnmatrix_set_btn_ctrl_all(mbox->btns, LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_NO_REPEAT);
125 
126         uint32_t btn_cnt = 0;
127         while(btn_txts[btn_cnt] && btn_txts[btn_cnt][0] != '\0') {
128             btn_cnt++;
129         }
130 
131         const lv_font_t * font = lv_obj_get_style_text_font(mbox->btns, LV_PART_ITEMS);
132         lv_coord_t btn_h = lv_font_get_line_height(font) + LV_DPI_DEF / 10;
133         lv_obj_set_size(mbox->btns, btn_cnt * (2 * LV_DPI_DEF / 3), btn_h);
134         lv_obj_set_style_max_width(mbox->btns, lv_pct(100), 0);
135         lv_obj_add_flag(mbox->btns, LV_OBJ_FLAG_EVENT_BUBBLE);    /*To see the event directly on the message box*/
136     }
137 
138     return obj;
139 }
140 
lv_msgbox_get_title(lv_obj_t * obj)141 lv_obj_t * lv_msgbox_get_title(lv_obj_t * obj)
142 {
143     LV_ASSERT_OBJ(obj, MY_CLASS);
144     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
145     return mbox->title;
146 }
147 
lv_msgbox_get_close_btn(lv_obj_t * obj)148 lv_obj_t * lv_msgbox_get_close_btn(lv_obj_t * obj)
149 {
150     LV_ASSERT_OBJ(obj, MY_CLASS);
151     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
152     return mbox->close_btn;
153 }
154 
lv_msgbox_get_text(lv_obj_t * obj)155 lv_obj_t * lv_msgbox_get_text(lv_obj_t * obj)
156 {
157     LV_ASSERT_OBJ(obj, MY_CLASS);
158     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
159     return mbox->text;
160 }
161 
lv_msgbox_get_content(lv_obj_t * obj)162 lv_obj_t * lv_msgbox_get_content(lv_obj_t * obj)
163 {
164     LV_ASSERT_OBJ(obj, MY_CLASS);
165     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
166     return mbox->content;
167 }
168 
lv_msgbox_get_btns(lv_obj_t * obj)169 lv_obj_t * lv_msgbox_get_btns(lv_obj_t * obj)
170 {
171     LV_ASSERT_OBJ(obj, MY_CLASS);
172     lv_msgbox_t * mbox = (lv_msgbox_t *)obj;
173     return mbox->btns;
174 }
175 
lv_msgbox_get_active_btn(lv_obj_t * mbox)176 uint16_t lv_msgbox_get_active_btn(lv_obj_t * mbox)
177 {
178     lv_obj_t * btnm = lv_msgbox_get_btns(mbox);
179     return lv_btnmatrix_get_selected_btn(btnm);
180 }
181 
lv_msgbox_get_active_btn_text(lv_obj_t * mbox)182 const char * lv_msgbox_get_active_btn_text(lv_obj_t * mbox)
183 {
184     lv_obj_t * btnm = lv_msgbox_get_btns(mbox);
185     return lv_btnmatrix_get_btn_text(btnm, lv_btnmatrix_get_selected_btn(btnm));
186 }
187 
lv_msgbox_close(lv_obj_t * mbox)188 void lv_msgbox_close(lv_obj_t * mbox)
189 {
190     if(lv_obj_has_flag(mbox, LV_MSGBOX_FLAG_AUTO_PARENT)) lv_obj_del(lv_obj_get_parent(mbox));
191     else lv_obj_del(mbox);
192 }
193 
lv_msgbox_close_async(lv_obj_t * dialog)194 void lv_msgbox_close_async(lv_obj_t * dialog)
195 {
196     if(lv_obj_has_flag(dialog, LV_MSGBOX_FLAG_AUTO_PARENT)) lv_obj_del_async(lv_obj_get_parent(dialog));
197     else lv_obj_del_async(dialog);
198 }
199 
200 /**********************
201  *   STATIC FUNCTIONS
202  **********************/
203 
msgbox_close_click_event_cb(lv_event_t * e)204 static void msgbox_close_click_event_cb(lv_event_t * e)
205 {
206     lv_obj_t * btn = lv_event_get_target(e);
207     lv_obj_t * mbox = lv_obj_get_parent(btn);
208     lv_msgbox_close(mbox);
209 }
210 
211 #endif /*LV_USE_MSGBOX*/
212