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 }