1 /**
2  * @file lv_cb.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_checkbox_private.h"
10 #include "../../core/lv_obj_private.h"
11 #include "../../core/lv_obj_class_private.h"
12 #if LV_USE_CHECKBOX != 0
13 
14 #include "../../misc/lv_assert.h"
15 #include "../../misc/lv_text_ap.h"
16 #include "../../core/lv_group.h"
17 #include "../../draw/lv_draw.h"
18 #include "../../stdlib/lv_string.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 #define MY_CLASS (&lv_checkbox_class)
24 
25 /**********************
26  *      TYPEDEFS
27  **********************/
28 
29 /**********************
30  *  STATIC PROTOTYPES
31  **********************/
32 static void lv_checkbox_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static void lv_checkbox_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
34 static void lv_checkbox_event(const lv_obj_class_t * class_p, lv_event_t * e);
35 static void lv_checkbox_draw(lv_event_t * e);
36 
37 /**********************
38  *  STATIC VARIABLES
39  **********************/
40 const lv_obj_class_t lv_checkbox_class = {
41     .constructor_cb = lv_checkbox_constructor,
42     .destructor_cb = lv_checkbox_destructor,
43     .event_cb = lv_checkbox_event,
44     .width_def = LV_SIZE_CONTENT,
45     .height_def = LV_SIZE_CONTENT,
46     .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
47     .instance_size = sizeof(lv_checkbox_t),
48     .base_class = &lv_obj_class,
49     .name = "checkbox",
50 };
51 
52 /**********************
53  *      MACROS
54  **********************/
55 
56 /**********************
57  *   GLOBAL FUNCTIONS
58  **********************/
59 
lv_checkbox_create(lv_obj_t * parent)60 lv_obj_t * lv_checkbox_create(lv_obj_t * parent)
61 {
62     LV_LOG_INFO("begin");
63     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
64     lv_obj_class_init_obj(obj);
65     return obj;
66 }
67 
68 /*=====================
69  * Setter functions
70  *====================*/
71 
lv_checkbox_set_text(lv_obj_t * obj,const char * txt)72 void lv_checkbox_set_text(lv_obj_t * obj, const char * txt)
73 {
74     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
75 
76     if(NULL != txt) {
77         size_t len;
78 
79 #if LV_USE_ARABIC_PERSIAN_CHARS
80         len = lv_text_ap_calc_bytes_count(txt) + 1;
81 #else
82         len = lv_strlen(txt) + 1;
83 #endif
84 
85         if(!cb->static_txt) cb->txt = lv_realloc(cb->txt, len);
86         else cb->txt = lv_malloc(len);
87 
88         LV_ASSERT_MALLOC(cb->txt);
89         if(NULL == cb->txt) return;
90 
91 #if LV_USE_ARABIC_PERSIAN_CHARS
92         lv_text_ap_proc(txt, cb->txt);
93 #else
94         lv_strcpy(cb->txt, txt);
95 #endif
96 
97         cb->static_txt = 0;
98     }
99 
100     lv_obj_refresh_self_size(obj);
101     lv_obj_invalidate(obj);
102 }
103 
lv_checkbox_set_text_static(lv_obj_t * obj,const char * txt)104 void lv_checkbox_set_text_static(lv_obj_t * obj, const char * txt)
105 {
106     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
107 
108     if(!cb->static_txt) lv_free(cb->txt);
109 
110     cb->txt = (char *)txt;
111     cb->static_txt = 1;
112 
113     lv_obj_refresh_self_size(obj);
114     lv_obj_invalidate(obj);
115 }
116 
117 /*=====================
118  * Getter functions
119  *====================*/
120 
lv_checkbox_get_text(const lv_obj_t * obj)121 const char * lv_checkbox_get_text(const lv_obj_t * obj)
122 {
123     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
124     return cb->txt;
125 }
126 
127 /**********************
128  *   STATIC FUNCTIONS
129  **********************/
130 
lv_checkbox_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)131 static void lv_checkbox_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
132 {
133     LV_UNUSED(class_p);
134     LV_TRACE_OBJ_CREATE("begin");
135 
136     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
137 
138 #if LV_WIDGETS_HAS_DEFAULT_VALUE
139     cb->txt = (char *)"Check box";
140     cb->static_txt = 1;
141 #else
142     cb->txt = (char *)"";
143     cb->static_txt = 1;
144 #endif
145 
146     lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE);
147     lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
148     lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
149     lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
150 
151     LV_TRACE_OBJ_CREATE("finished");
152 }
153 
lv_checkbox_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)154 static void lv_checkbox_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
155 {
156     LV_UNUSED(class_p);
157     LV_TRACE_OBJ_CREATE("begin");
158 
159     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
160     if(!cb->static_txt) {
161         lv_free(cb->txt);
162         cb->txt = NULL;
163     }
164     LV_TRACE_OBJ_CREATE("finished");
165 }
166 
lv_checkbox_event(const lv_obj_class_t * class_p,lv_event_t * e)167 static void lv_checkbox_event(const lv_obj_class_t * class_p, lv_event_t * e)
168 {
169     LV_UNUSED(class_p);
170 
171     lv_result_t res;
172     /*Call the ancestor's event handler*/
173     res = lv_obj_event_base(MY_CLASS, e);
174     if(res != LV_RESULT_OK) return;
175 
176     lv_event_code_t code = lv_event_get_code(e);
177     lv_obj_t * obj = lv_event_get_current_target(e);
178 
179     if(code == LV_EVENT_GET_SELF_SIZE) {
180         lv_point_t * p = lv_event_get_param(e);
181         lv_checkbox_t * cb = (lv_checkbox_t *)obj;
182 
183         const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
184         int32_t font_h = lv_font_get_line_height(font);
185         int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
186         int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
187 
188         lv_point_t txt_size;
189         lv_text_get_size(&txt_size, cb->txt, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
190 
191         int32_t bg_colp = lv_obj_get_style_pad_column(obj, LV_PART_MAIN);
192         int32_t marker_leftp = lv_obj_get_style_pad_left(obj, LV_PART_INDICATOR);
193         int32_t marker_rightp = lv_obj_get_style_pad_right(obj, LV_PART_INDICATOR);
194         int32_t marker_topp = lv_obj_get_style_pad_top(obj, LV_PART_INDICATOR);
195         int32_t marker_bottomp = lv_obj_get_style_pad_bottom(obj, LV_PART_INDICATOR);
196         lv_point_t marker_size;
197         marker_size.x = font_h + marker_leftp + marker_rightp;
198         marker_size.y = font_h + marker_topp + marker_bottomp;
199 
200         p->x = marker_size.x + txt_size.x + bg_colp;
201         p->y = LV_MAX(marker_size.y, txt_size.y);
202     }
203     else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
204         int32_t * s = lv_event_get_param(e);
205         int32_t m = lv_obj_calculate_ext_draw_size(obj, LV_PART_INDICATOR);
206         *s = LV_MAX(*s, m);
207     }
208     else if(code == LV_EVENT_DRAW_MAIN) {
209         lv_checkbox_draw(e);
210     }
211 }
212 
lv_checkbox_draw(lv_event_t * e)213 static void lv_checkbox_draw(lv_event_t * e)
214 {
215     lv_obj_t * obj = lv_event_get_current_target(e);
216     lv_checkbox_t * cb = (lv_checkbox_t *)obj;
217 
218     lv_layer_t * layer = lv_event_get_layer(e);
219     const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
220     int32_t font_h = lv_font_get_line_height(font);
221 
222     const bool is_rtl = LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
223 
224     int32_t bg_border = lv_obj_get_style_border_width(obj, LV_PART_MAIN);
225     int32_t bg_topp = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + bg_border;
226     int32_t bg_p = is_rtl ? lv_obj_get_style_pad_right(obj, LV_PART_MAIN) : lv_obj_get_style_pad_left(obj,
227                                                                                                       LV_PART_MAIN) + bg_border;
228     int32_t bg_colp = lv_obj_get_style_pad_column(obj, LV_PART_MAIN);
229 
230     int32_t marker_leftp = lv_obj_get_style_pad_left(obj, LV_PART_INDICATOR);
231     int32_t marker_rightp = lv_obj_get_style_pad_right(obj, LV_PART_INDICATOR);
232     int32_t marker_topp = lv_obj_get_style_pad_top(obj, LV_PART_INDICATOR);
233     int32_t marker_bottomp = lv_obj_get_style_pad_bottom(obj, LV_PART_INDICATOR);
234 
235     int32_t transf_w = lv_obj_get_style_transform_width(obj, LV_PART_INDICATOR);
236     int32_t transf_h = lv_obj_get_style_transform_height(obj, LV_PART_INDICATOR);
237 
238     lv_draw_rect_dsc_t indic_dsc;
239     lv_draw_rect_dsc_init(&indic_dsc);
240     indic_dsc.base.layer = layer;
241     lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &indic_dsc);
242     lv_area_t marker_area;
243     if(is_rtl) {
244         marker_area.x2 = obj->coords.x2 - bg_p;
245         marker_area.x1 = marker_area.x2 - font_h - marker_leftp - marker_rightp + 1;
246     }
247     else {
248         marker_area.x1 = obj->coords.x1 + bg_p;
249         marker_area.x2 = marker_area.x1 + font_h + marker_leftp + marker_rightp - 1;
250     }
251     marker_area.y1 = obj->coords.y1 + bg_topp;
252     marker_area.y2 = marker_area.y1 + font_h + marker_topp + marker_bottomp - 1;
253 
254     lv_area_t marker_area_transf;
255     lv_area_copy(&marker_area_transf, &marker_area);
256     lv_area_increase(&marker_area_transf, transf_w, transf_h);
257 
258     lv_draw_rect(layer, &indic_dsc, &marker_area_transf);
259 
260     int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
261     int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
262 
263     lv_point_t txt_size;
264     lv_text_get_size(&txt_size, cb->txt, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
265 
266     lv_draw_label_dsc_t txt_dsc;
267     lv_draw_label_dsc_init(&txt_dsc);
268     txt_dsc.base.layer = layer;
269     lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &txt_dsc);
270     txt_dsc.text = cb->txt;
271 
272     int32_t y_ofs = (lv_area_get_height(&marker_area) - font_h) / 2;
273     lv_area_t txt_area;
274     if(is_rtl) {
275         txt_area.x2 = marker_area.x1 - bg_colp;
276         txt_area.x1 = txt_area.x2 - txt_size.x;
277     }
278     else {
279         txt_area.x1 = marker_area.x2 + bg_colp;
280         txt_area.x2 = txt_area.x1 + txt_size.x;
281     }
282     txt_area.y1 = obj->coords.y1 + bg_topp + y_ofs;
283     txt_area.y2 = txt_area.y1 + txt_size.y;
284 
285     lv_draw_label(layer, &txt_dsc, &txt_area);
286 }
287 #endif
288