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_obj_tree.c (12430B)
1 /** 2 * @file lv_obj_tree.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include <stdlib.h> 10 11 #include "lv_obj.h" 12 #include "lv_indev.h" 13 #include "../misc/lv_anim.h" 14 #include "../misc/lv_gc.h" 15 #include "../misc/lv_async.h" 16 17 /********************* 18 * DEFINES 19 *********************/ 20 #define MY_CLASS &lv_obj_class 21 22 /********************** 23 * TYPEDEFS 24 **********************/ 25 26 /********************** 27 * STATIC PROTOTYPES 28 **********************/ 29 static void lv_obj_del_async_cb(void * obj); 30 static void obj_del_core(lv_obj_t * obj); 31 static lv_obj_tree_walk_res_t walk_core(lv_obj_t * obj, lv_obj_tree_walk_cb_t cb, void * user_data); 32 33 /********************** 34 * STATIC VARIABLES 35 **********************/ 36 37 /********************** 38 * MACROS 39 **********************/ 40 41 /********************** 42 * GLOBAL FUNCTIONS 43 **********************/ 44 45 void lv_obj_del(lv_obj_t * obj) 46 { 47 LV_LOG_TRACE("begin (delete %p)", (void *)obj); 48 LV_ASSERT_OBJ(obj, MY_CLASS); 49 lv_obj_invalidate(obj); 50 51 lv_obj_t * par = lv_obj_get_parent(obj); 52 if(par) { 53 lv_obj_scrollbar_invalidate(par); 54 } 55 56 lv_disp_t * disp = NULL; 57 bool act_scr_del = false; 58 if(par == NULL) { 59 disp = lv_obj_get_disp(obj); 60 if(!disp) return; /*Shouldn't happen*/ 61 if(disp->act_scr == obj) act_scr_del = true; 62 } 63 64 obj_del_core(obj); 65 66 /*Call the ancestor's event handler to the parent to notify it about the child delete*/ 67 if(par) { 68 lv_obj_update_layout(par); 69 lv_obj_readjust_scroll(par, LV_ANIM_OFF); 70 lv_obj_scrollbar_invalidate(par); 71 lv_event_send(par, LV_EVENT_CHILD_CHANGED, NULL); 72 lv_event_send(par, LV_EVENT_CHILD_DELETED, NULL); 73 } 74 75 /*Handle if the active screen was deleted*/ 76 if(act_scr_del) { 77 LV_LOG_WARN("the active screen was deleted"); 78 disp->act_scr = NULL; 79 } 80 81 LV_ASSERT_MEM_INTEGRITY(); 82 LV_LOG_TRACE("finished (delete %p)", (void *)obj); 83 } 84 85 void lv_obj_clean(lv_obj_t * obj) 86 { 87 LV_LOG_TRACE("begin (delete %p)", (void *)obj); 88 LV_ASSERT_OBJ(obj, MY_CLASS); 89 90 lv_obj_invalidate(obj); 91 92 lv_obj_t * child = lv_obj_get_child(obj, 0); 93 while(child) { 94 obj_del_core(child); 95 child = lv_obj_get_child(obj, 0); 96 } 97 /*Just to remove scroll animations if any*/ 98 lv_obj_scroll_to(obj, 0, 0, LV_ANIM_OFF); 99 if(obj->spec_attr) { 100 obj->spec_attr->scroll.x = 0; 101 obj->spec_attr->scroll.y = 0; 102 } 103 104 LV_ASSERT_MEM_INTEGRITY(); 105 106 LV_LOG_TRACE("finished (delete %p)", (void *)obj); 107 } 108 109 void lv_obj_del_delayed(lv_obj_t * obj, uint32_t delay_ms) 110 { 111 lv_anim_t a; 112 lv_anim_init(&a); 113 lv_anim_set_var(&a, obj); 114 lv_anim_set_exec_cb(&a, NULL); 115 lv_anim_set_time(&a, 1); 116 lv_anim_set_delay(&a, delay_ms); 117 lv_anim_set_ready_cb(&a, lv_obj_del_anim_ready_cb); 118 lv_anim_start(&a); 119 } 120 121 void lv_obj_del_anim_ready_cb(lv_anim_t * a) 122 { 123 lv_obj_del(a->var); 124 } 125 126 void lv_obj_del_async(lv_obj_t * obj) 127 { 128 LV_ASSERT_OBJ(obj, MY_CLASS); 129 lv_async_call(lv_obj_del_async_cb, obj); 130 } 131 132 void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) 133 { 134 LV_ASSERT_OBJ(obj, MY_CLASS); 135 LV_ASSERT_OBJ(parent, MY_CLASS); 136 137 if(obj->parent == NULL) { 138 LV_LOG_WARN("Can't set the parent of a screen"); 139 return; 140 } 141 142 if(parent == NULL) { 143 LV_LOG_WARN("Can't set parent == NULL to an object"); 144 return; 145 } 146 147 lv_obj_invalidate(obj); 148 149 lv_obj_allocate_spec_attr(parent); 150 151 lv_obj_t * old_parent = obj->parent; 152 /*Remove the object from the old parent's child list*/ 153 int32_t i; 154 for(i = lv_obj_get_index(obj); i <= (int32_t)lv_obj_get_child_cnt(old_parent) - 2; i++) { 155 old_parent->spec_attr->children[i] = old_parent->spec_attr->children[i + 1]; 156 } 157 old_parent->spec_attr->child_cnt--; 158 if(old_parent->spec_attr->child_cnt) { 159 old_parent->spec_attr->children = lv_mem_realloc(old_parent->spec_attr->children, 160 old_parent->spec_attr->child_cnt * (sizeof(lv_obj_t *))); 161 } 162 else { 163 lv_mem_free(old_parent->spec_attr->children); 164 old_parent->spec_attr->children = NULL; 165 } 166 167 /*Add the child to the new parent as the last (newest child)*/ 168 parent->spec_attr->child_cnt++; 169 parent->spec_attr->children = lv_mem_realloc(parent->spec_attr->children, 170 parent->spec_attr->child_cnt * (sizeof(lv_obj_t *))); 171 parent->spec_attr->children[lv_obj_get_child_cnt(parent) - 1] = obj; 172 173 obj->parent = parent; 174 175 /*Notify the original parent because one of its children is lost*/ 176 lv_obj_readjust_scroll(old_parent, LV_ANIM_OFF); 177 lv_obj_scrollbar_invalidate(old_parent); 178 lv_event_send(old_parent, LV_EVENT_CHILD_CHANGED, obj); 179 lv_event_send(old_parent, LV_EVENT_CHILD_DELETED, NULL); 180 181 /*Notify the new parent about the child*/ 182 lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj); 183 lv_event_send(parent, LV_EVENT_CHILD_CREATED, NULL); 184 185 lv_obj_mark_layout_as_dirty(obj); 186 187 lv_obj_invalidate(obj); 188 } 189 190 void lv_obj_move_to_index(lv_obj_t * obj, int32_t index) 191 { 192 LV_ASSERT_OBJ(obj, MY_CLASS); 193 194 if(index < 0) { 195 index = lv_obj_get_child_cnt(lv_obj_get_parent(obj)) + index; 196 } 197 198 const int32_t old_index = lv_obj_get_index(obj); 199 200 lv_obj_t * parent = lv_obj_get_parent(obj); 201 202 if(index < 0) return; 203 if(index >= (int32_t) lv_obj_get_child_cnt(parent)) return; 204 if(index == old_index) return; 205 206 int32_t i = old_index; 207 if(index < old_index) { 208 while(i > index) { 209 parent->spec_attr->children[i] = parent->spec_attr->children[i - 1]; 210 i--; 211 } 212 } 213 else { 214 while(i < index) { 215 parent->spec_attr->children[i] = parent->spec_attr->children[i + 1]; 216 i++; 217 } 218 } 219 220 parent->spec_attr->children[index] = obj; 221 lv_event_send(parent, LV_EVENT_CHILD_CHANGED, NULL); 222 lv_obj_invalidate(parent); 223 } 224 225 void lv_obj_swap(lv_obj_t * obj1, lv_obj_t * obj2) 226 { 227 LV_ASSERT_OBJ(obj1, MY_CLASS); 228 LV_ASSERT_OBJ(obj2, MY_CLASS); 229 230 lv_obj_t * parent = lv_obj_get_parent(obj1); 231 lv_obj_t * parent2 = lv_obj_get_parent(obj2); 232 233 uint_fast32_t index1 = lv_obj_get_index(obj1); 234 uint_fast32_t index2 = lv_obj_get_index(obj2); 235 236 lv_event_send(parent2, LV_EVENT_CHILD_DELETED, obj2); 237 lv_event_send(parent, LV_EVENT_CHILD_DELETED, obj1); 238 239 parent->spec_attr->children[index1] = obj2; 240 parent2->spec_attr->children[index2] = obj1; 241 242 lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj2); 243 lv_event_send(parent, LV_EVENT_CHILD_CREATED, obj2); 244 lv_event_send(parent2, LV_EVENT_CHILD_CHANGED, obj1); 245 lv_event_send(parent2, LV_EVENT_CHILD_CREATED, obj1); 246 247 lv_obj_invalidate(parent); 248 249 if(parent != parent2) { 250 lv_obj_invalidate(parent2); 251 } 252 lv_group_swap_obj(obj1, obj2); 253 } 254 255 lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj) 256 { 257 LV_ASSERT_OBJ(obj, MY_CLASS); 258 259 const lv_obj_t * par = obj; 260 const lv_obj_t * act_par; 261 262 do { 263 act_par = par; 264 par = lv_obj_get_parent(act_par); 265 } while(par != NULL); 266 267 return (lv_obj_t *)act_par; 268 } 269 270 lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj) 271 { 272 LV_ASSERT_OBJ(obj, MY_CLASS); 273 274 const lv_obj_t * scr; 275 276 if(obj->parent == NULL) scr = obj; /*`obj` is a screen*/ 277 else scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/ 278 279 lv_disp_t * d; 280 _LV_LL_READ(&LV_GC_ROOT(_lv_disp_ll), d) { 281 uint32_t i; 282 for(i = 0; i < d->screen_cnt; i++) { 283 if(d->screens[i] == scr) return d; 284 } 285 } 286 287 LV_LOG_WARN("No screen found"); 288 return NULL; 289 } 290 291 lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj) 292 { 293 if(obj == NULL) return NULL; 294 LV_ASSERT_OBJ(obj, MY_CLASS); 295 296 return obj->parent; 297 } 298 299 lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, int32_t id) 300 { 301 LV_ASSERT_OBJ(obj, MY_CLASS); 302 303 if(obj->spec_attr == NULL) return NULL; 304 305 uint32_t idu; 306 if(id < 0) { 307 id = obj->spec_attr->child_cnt + id; 308 if(id < 0) return NULL; 309 idu = (uint32_t) id; 310 } 311 else { 312 idu = id; 313 } 314 315 if(idu >= obj->spec_attr->child_cnt) return NULL; 316 else return obj->spec_attr->children[id]; 317 } 318 319 uint32_t lv_obj_get_child_cnt(const lv_obj_t * obj) 320 { 321 LV_ASSERT_OBJ(obj, MY_CLASS); 322 if(obj->spec_attr == NULL) return 0; 323 return obj->spec_attr->child_cnt; 324 } 325 326 uint32_t lv_obj_get_index(const lv_obj_t * obj) 327 { 328 LV_ASSERT_OBJ(obj, MY_CLASS); 329 330 lv_obj_t * parent = lv_obj_get_parent(obj); 331 if(parent == NULL) return 0; 332 333 uint32_t i = 0; 334 for(i = 0; i < lv_obj_get_child_cnt(parent); i++) { 335 if(lv_obj_get_child(parent, i) == obj) return i; 336 } 337 338 return 0xFFFFFFFF; /*Shouldn't happen*/ 339 } 340 341 void lv_obj_tree_walk(lv_obj_t * start_obj, lv_obj_tree_walk_cb_t cb, void * user_data) 342 { 343 walk_core(start_obj, cb, user_data); 344 } 345 346 /********************** 347 * STATIC FUNCTIONS 348 **********************/ 349 350 static void lv_obj_del_async_cb(void * obj) 351 { 352 LV_ASSERT_OBJ(obj, MY_CLASS); 353 354 lv_obj_del(obj); 355 } 356 357 static void obj_del_core(lv_obj_t * obj) 358 { 359 /*Let the user free the resources used in `LV_EVENT_DELETE`*/ 360 lv_res_t res = lv_event_send(obj, LV_EVENT_DELETE, NULL); 361 if(res == LV_RES_INV) return; 362 363 /*Recursively delete the children*/ 364 lv_obj_t * child = lv_obj_get_child(obj, 0); 365 while(child) { 366 obj_del_core(child); 367 child = lv_obj_get_child(obj, 0); 368 } 369 370 lv_group_t * group = lv_obj_get_group(obj); 371 372 /*Reset all input devices if the object to delete is used*/ 373 lv_indev_t * indev = lv_indev_get_next(NULL); 374 while(indev) { 375 if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) { 376 lv_indev_reset(indev, obj); 377 } 378 if(indev->proc.types.pointer.last_pressed == obj) { 379 indev->proc.types.pointer.last_pressed = NULL; 380 } 381 382 if(indev->group == group && obj == lv_indev_get_obj_act()) { 383 lv_indev_reset(indev, obj); 384 } 385 indev = lv_indev_get_next(indev); 386 } 387 388 /*All children deleted. Now clean up the object specific data*/ 389 _lv_obj_destruct(obj); 390 391 /*Remove the screen for the screen list*/ 392 if(obj->parent == NULL) { 393 lv_disp_t * disp = lv_obj_get_disp(obj); 394 uint32_t i; 395 /*Find the screen in the list*/ 396 for(i = 0; i < disp->screen_cnt; i++) { 397 if(disp->screens[i] == obj) break; 398 } 399 400 uint32_t id = i; 401 for(i = id; i < disp->screen_cnt - 1; i++) { 402 disp->screens[i] = disp->screens[i + 1]; 403 } 404 disp->screen_cnt--; 405 disp->screens = lv_mem_realloc(disp->screens, disp->screen_cnt * sizeof(lv_obj_t *)); 406 } 407 /*Remove the object from the child list of its parent*/ 408 else { 409 uint32_t id = lv_obj_get_index(obj); 410 uint32_t i; 411 for(i = id; i < obj->parent->spec_attr->child_cnt - 1; i++) { 412 obj->parent->spec_attr->children[i] = obj->parent->spec_attr->children[i + 1]; 413 } 414 obj->parent->spec_attr->child_cnt--; 415 obj->parent->spec_attr->children = lv_mem_realloc(obj->parent->spec_attr->children, 416 obj->parent->spec_attr->child_cnt * sizeof(lv_obj_t *)); 417 } 418 419 /*Free the object itself*/ 420 lv_mem_free(obj); 421 } 422 423 424 static lv_obj_tree_walk_res_t walk_core(lv_obj_t * obj, lv_obj_tree_walk_cb_t cb, void * user_data) 425 { 426 lv_obj_tree_walk_res_t res = LV_OBJ_TREE_WALK_NEXT; 427 428 if(obj == NULL) { 429 lv_disp_t * disp = lv_disp_get_next(NULL); 430 while(disp) { 431 uint32_t i; 432 for(i = 0; i < disp->screen_cnt; i++) { 433 walk_core(disp->screens[i], cb, user_data); 434 } 435 disp = lv_disp_get_next(disp); 436 } 437 return LV_OBJ_TREE_WALK_END; /*The value doesn't matter as it wasn't called recursively*/ 438 } 439 440 res = cb(obj, user_data); 441 442 if(res == LV_OBJ_TREE_WALK_END) return LV_OBJ_TREE_WALK_END; 443 444 if(res != LV_OBJ_TREE_WALK_SKIP_CHILDREN) { 445 uint32_t i; 446 for(i = 0; i < lv_obj_get_child_cnt(obj); i++) { 447 res = walk_core(lv_obj_get_child(obj, i), cb, user_data); 448 if(res == LV_OBJ_TREE_WALK_END) return LV_OBJ_TREE_WALK_END; 449 } 450 } 451 return LV_OBJ_TREE_WALK_NEXT; 452 }