acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_tabview.c (10041B)
1 /** 2 * @file lv_tabview.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_tabview.h" 10 #if LV_USE_TABVIEW 11 12 #include "../../../misc/lv_assert.h" 13 14 /********************* 15 * DEFINES 16 *********************/ 17 #define MY_CLASS &lv_tabview_class 18 19 /********************** 20 * TYPEDEFS 21 **********************/ 22 23 /********************** 24 * STATIC PROTOTYPES 25 **********************/ 26 static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 27 static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 28 static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e); 29 static void btns_value_changed_event_cb(lv_event_t * e); 30 static void cont_scroll_end_event_cb(lv_event_t * e); 31 32 /********************** 33 * STATIC VARIABLES 34 **********************/ 35 const lv_obj_class_t lv_tabview_class = { 36 .constructor_cb = lv_tabview_constructor, 37 .destructor_cb = lv_tabview_destructor, 38 .event_cb = lv_tabview_event, 39 .width_def = LV_PCT(100), 40 .height_def = LV_PCT(100), 41 .base_class = &lv_obj_class, 42 .instance_size = sizeof(lv_tabview_t) 43 }; 44 45 static lv_dir_t tabpos_create; 46 static lv_coord_t tabsize_create; 47 48 /********************** 49 * MACROS 50 **********************/ 51 52 /********************** 53 * GLOBAL FUNCTIONS 54 **********************/ 55 56 lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, lv_coord_t tab_size) 57 { 58 LV_LOG_INFO("begin"); 59 tabpos_create = tab_pos; 60 tabsize_create = tab_size; 61 62 lv_obj_t * obj = lv_obj_class_create_obj(&lv_tabview_class, parent); 63 lv_obj_class_init_obj(obj); 64 return obj; 65 } 66 67 lv_obj_t * lv_tabview_add_tab(lv_obj_t * obj, const char * name) 68 { 69 LV_ASSERT_OBJ(obj, MY_CLASS); 70 lv_tabview_t * tabview = (lv_tabview_t *)obj; 71 lv_obj_t * cont = lv_tabview_get_content(obj); 72 73 lv_obj_t * page = lv_obj_create(cont); 74 lv_obj_set_size(page, LV_PCT(100), LV_PCT(100)); 75 lv_obj_clear_flag(page, LV_OBJ_FLAG_CLICK_FOCUSABLE); 76 uint32_t tab_id = lv_obj_get_child_cnt(cont); 77 78 lv_obj_t * btns = lv_tabview_get_tab_btns(obj); 79 80 char ** old_map = tabview->map; 81 char ** new_map; 82 83 /*top or bottom dir*/ 84 if(tabview->tab_pos & LV_DIR_VER) { 85 new_map = lv_mem_alloc((tab_id + 1) * sizeof(const char *)); 86 lv_memcpy_small(new_map, old_map, sizeof(const char *) * (tab_id - 1)); 87 new_map[tab_id - 1] = lv_mem_alloc(strlen(name) + 1); 88 strcpy((char *)new_map[tab_id - 1], name); 89 new_map[tab_id] = ""; 90 } 91 /*left or right dir*/ 92 else { 93 new_map = lv_mem_alloc((tab_id * 2) * sizeof(const char *)); 94 lv_memcpy_small(new_map, old_map, sizeof(const char *) * (tab_id - 1) * 2); 95 if(tabview->tab_cnt == 0) { 96 new_map[0] = lv_mem_alloc(strlen(name) + 1); 97 strcpy((char *)new_map[0], name); 98 new_map[1] = ""; 99 } 100 else { 101 new_map[tab_id * 2 - 3] = "\n"; 102 new_map[tab_id * 2 - 2] = lv_mem_alloc(strlen(name) + 1); 103 new_map[tab_id * 2 - 1] = ""; 104 strcpy((char *)new_map[(tab_id * 2) - 2], name); 105 } 106 } 107 tabview->map = new_map; 108 lv_btnmatrix_set_map(btns, (const char **)new_map); 109 lv_mem_free(old_map); 110 111 lv_btnmatrix_set_btn_ctrl_all(btns, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_CLICK_TRIG | 112 LV_BTNMATRIX_CTRL_NO_REPEAT); 113 114 tabview->tab_cnt++; 115 if(tabview->tab_cnt == 1) { 116 lv_tabview_set_act(obj, 0, LV_ANIM_OFF); 117 } 118 119 lv_btnmatrix_set_btn_ctrl(btns, tabview->tab_cur, LV_BTNMATRIX_CTRL_CHECKED); 120 121 return page; 122 } 123 124 void lv_tabview_set_act(lv_obj_t * obj, uint32_t id, lv_anim_enable_t anim_en) 125 { 126 LV_ASSERT_OBJ(obj, MY_CLASS); 127 lv_tabview_t * tabview = (lv_tabview_t *)obj; 128 129 if(id >= tabview->tab_cnt) { 130 id = tabview->tab_cnt - 1; 131 } 132 133 /*To be sure lv_obj_get_content_width will return valid value*/ 134 lv_obj_update_layout(obj); 135 136 lv_obj_t * cont = lv_tabview_get_content(obj); 137 if(cont == NULL) return; 138 139 if((tabview->tab_pos & LV_DIR_VER) != 0) { 140 lv_coord_t gap = lv_obj_get_style_pad_column(cont, LV_PART_MAIN); 141 lv_coord_t w = lv_obj_get_content_width(cont); 142 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) { 143 lv_obj_scroll_to_x(cont, id * (gap + w), anim_en); 144 } 145 else { 146 int32_t id_rtl = -(int32_t)id; 147 lv_obj_scroll_to_x(cont, (gap + w) * id_rtl, anim_en); 148 } 149 } 150 else { 151 lv_coord_t gap = lv_obj_get_style_pad_row(cont, LV_PART_MAIN); 152 lv_coord_t h = lv_obj_get_content_height(cont); 153 lv_obj_scroll_to_y(cont, id * (gap + h), anim_en); 154 } 155 156 lv_obj_t * btns = lv_tabview_get_tab_btns(obj); 157 lv_btnmatrix_set_btn_ctrl(btns, id, LV_BTNMATRIX_CTRL_CHECKED); 158 tabview->tab_cur = id; 159 } 160 161 uint16_t lv_tabview_get_tab_act(lv_obj_t * obj) 162 { 163 LV_ASSERT_OBJ(obj, MY_CLASS); 164 lv_tabview_t * tabview = (lv_tabview_t *)obj; 165 return tabview->tab_cur; 166 } 167 168 lv_obj_t * lv_tabview_get_content(lv_obj_t * tv) 169 { 170 return lv_obj_get_child(tv, 1); 171 } 172 173 lv_obj_t * lv_tabview_get_tab_btns(lv_obj_t * tv) 174 { 175 return lv_obj_get_child(tv, 0); 176 } 177 178 /********************** 179 * STATIC FUNCTIONS 180 **********************/ 181 182 static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 183 { 184 LV_UNUSED(class_p); 185 lv_tabview_t * tabview = (lv_tabview_t *)obj; 186 187 tabview->tab_pos = tabpos_create; 188 189 switch(tabview->tab_pos) { 190 case LV_DIR_TOP: 191 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); 192 break; 193 case LV_DIR_BOTTOM: 194 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN_REVERSE); 195 break; 196 case LV_DIR_LEFT: 197 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); 198 break; 199 case LV_DIR_RIGHT: 200 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_REVERSE); 201 break; 202 } 203 204 lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100)); 205 206 lv_obj_t * btnm; 207 lv_obj_t * cont; 208 209 btnm = lv_btnmatrix_create(obj); 210 cont = lv_obj_create(obj); 211 212 lv_btnmatrix_set_one_checked(btnm, true); 213 tabview->map = lv_mem_alloc(sizeof(const char *)); 214 tabview->map[0] = ""; 215 lv_btnmatrix_set_map(btnm, (const char **)tabview->map); 216 lv_obj_add_event_cb(btnm, btns_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); 217 lv_obj_add_flag(btnm, LV_OBJ_FLAG_EVENT_BUBBLE); 218 219 lv_obj_add_event_cb(cont, cont_scroll_end_event_cb, LV_EVENT_ALL, NULL); 220 lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF); 221 222 switch(tabview->tab_pos) { 223 case LV_DIR_TOP: 224 case LV_DIR_BOTTOM: 225 lv_obj_set_size(btnm, LV_PCT(100), tabsize_create); 226 lv_obj_set_width(cont, LV_PCT(100)); 227 lv_obj_set_flex_grow(cont, 1); 228 break; 229 case LV_DIR_LEFT: 230 case LV_DIR_RIGHT: 231 lv_obj_set_size(btnm, tabsize_create, LV_PCT(100)); 232 lv_obj_set_height(cont, LV_PCT(100)); 233 lv_obj_set_flex_grow(cont, 1); 234 break; 235 } 236 237 lv_group_t * g = lv_group_get_default(); 238 if(g) lv_group_add_obj(g, btnm); 239 240 if((tabview->tab_pos & LV_DIR_VER) != 0) { 241 lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); 242 lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_CENTER); 243 } 244 else { 245 lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); 246 lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER); 247 } 248 lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLL_ONE); 249 lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLL_ON_FOCUS); 250 } 251 252 static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 253 { 254 LV_UNUSED(class_p); 255 lv_tabview_t * tabview = (lv_tabview_t *)obj; 256 257 uint32_t i; 258 if(tabview->tab_pos & LV_DIR_VER) { 259 for(i = 0; i < tabview->tab_cnt; i++) { 260 lv_mem_free(tabview->map[i]); 261 tabview->map[i] = NULL; 262 } 263 } 264 if(tabview->tab_pos & LV_DIR_HOR) { 265 for(i = 0; i < tabview->tab_cnt; i++) { 266 lv_mem_free(tabview->map[i * 2]); 267 tabview->map[i * 2] = NULL; 268 } 269 } 270 271 272 lv_mem_free(tabview->map); 273 tabview->map = NULL; 274 } 275 276 static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e) 277 { 278 LV_UNUSED(class_p); 279 lv_res_t res = lv_obj_event_base(&lv_tabview_class, e); 280 if(res != LV_RES_OK) return; 281 282 lv_event_code_t code = lv_event_get_code(e); 283 lv_obj_t * target = lv_event_get_target(e); 284 285 if(code == LV_EVENT_SIZE_CHANGED) { 286 lv_tabview_set_act(target, lv_tabview_get_tab_act(target), LV_ANIM_OFF); 287 } 288 } 289 290 291 static void btns_value_changed_event_cb(lv_event_t * e) 292 { 293 lv_obj_t * btns = lv_event_get_target(e); 294 295 lv_obj_t * tv = lv_obj_get_parent(btns); 296 uint32_t id = lv_btnmatrix_get_selected_btn(btns); 297 lv_tabview_set_act(tv, id, LV_ANIM_ON); 298 } 299 300 static void cont_scroll_end_event_cb(lv_event_t * e) 301 { 302 lv_obj_t * cont = lv_event_get_target(e); 303 lv_event_code_t code = lv_event_get_code(e); 304 305 lv_obj_t * tv = lv_obj_get_parent(cont); 306 lv_tabview_t * tv_obj = (lv_tabview_t *)tv; 307 if(code == LV_EVENT_LAYOUT_CHANGED) { 308 lv_tabview_set_act(tv, lv_tabview_get_tab_act(tv), LV_ANIM_OFF); 309 } 310 else if(code == LV_EVENT_SCROLL_END) { 311 lv_point_t p; 312 lv_obj_get_scroll_end(cont, &p); 313 314 lv_coord_t t; 315 if((tv_obj->tab_pos & LV_DIR_VER) != 0) { 316 lv_coord_t w = lv_obj_get_content_width(cont); 317 if(lv_obj_get_style_base_dir(tv, LV_PART_MAIN) == LV_BASE_DIR_RTL) t = -(p.x - w / 2) / w; 318 else t = (p.x + w / 2) / w; 319 } 320 else { 321 lv_coord_t h = lv_obj_get_content_height(cont); 322 t = (p.y + h / 2) / h; 323 } 324 325 if(t < 0) t = 0; 326 bool new_tab = false; 327 if(t != lv_tabview_get_tab_act(tv)) new_tab = true; 328 lv_tabview_set_act(tv, t, LV_ANIM_ON); 329 330 if(new_tab) lv_event_send(tv, LV_EVENT_VALUE_CHANGED, NULL); 331 } 332 } 333 #endif /*LV_USE_TABVIEW*/