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