/** * @file lv_fragment_manager.c * */ /********************* * INCLUDES *********************/ #include "lv_fragment.h" #if LV_USE_FRAGMENT #include "../../../misc/lv_ll.h" /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ typedef struct _lv_fragment_stack_item_t { lv_fragment_managed_states_t * states; } lv_fragment_stack_item_t; struct _lv_fragment_manager_t { lv_fragment_t * parent; /** * Linked list to store attached fragments */ lv_ll_t attached; /** * Linked list to store fragments in stack */ lv_ll_t stack; }; /********************** * STATIC PROTOTYPES **********************/ static void item_create_obj(lv_fragment_managed_states_t * item); static void item_del_obj(lv_fragment_managed_states_t * item); static void item_del_fragment(lv_fragment_managed_states_t * item); static lv_fragment_managed_states_t * fragment_attach(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container); /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ lv_fragment_manager_t * lv_fragment_manager_create(lv_fragment_t * parent) { lv_fragment_manager_t * instance = lv_mem_alloc(sizeof(lv_fragment_manager_t)); lv_memset_00(instance, sizeof(lv_fragment_manager_t)); instance->parent = parent; _lv_ll_init(&instance->attached, sizeof(lv_fragment_managed_states_t)); _lv_ll_init(&instance->stack, sizeof(lv_fragment_stack_item_t)); return instance; } void lv_fragment_manager_del(lv_fragment_manager_t * manager) { LV_ASSERT_NULL(manager); lv_fragment_managed_states_t * states; _LV_LL_READ_BACK(&manager->attached, states) { item_del_obj(states); item_del_fragment(states); } _lv_ll_clear(&manager->attached); _lv_ll_clear(&manager->stack); lv_mem_free(manager); } void lv_fragment_manager_create_obj(lv_fragment_manager_t * manager) { LV_ASSERT_NULL(manager); lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack); lv_fragment_managed_states_t * states = NULL; _LV_LL_READ(&manager->attached, states) { if(states->in_stack && top->states != states) { /*Only create obj for top item in stack*/ continue; } item_create_obj(states); } } void lv_fragment_manager_del_obj(lv_fragment_manager_t * manager) { LV_ASSERT_NULL(manager); lv_fragment_managed_states_t * states = NULL; _LV_LL_READ_BACK(&manager->attached, states) { item_del_obj(states); } } void lv_fragment_manager_add(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container) { lv_fragment_managed_states_t * states = fragment_attach(manager, fragment, container); if(!manager->parent || manager->parent->managed->obj_created) { item_create_obj(states); } } void lv_fragment_manager_remove(lv_fragment_manager_t * manager, lv_fragment_t * fragment) { LV_ASSERT_NULL(manager); LV_ASSERT_NULL(fragment); LV_ASSERT_NULL(fragment->managed); LV_ASSERT(fragment->managed->manager == manager); lv_fragment_managed_states_t * states = fragment->managed; lv_fragment_managed_states_t * prev = NULL; bool was_top = false; if(states->in_stack) { void * stack_top = _lv_ll_get_tail(&manager->stack); lv_fragment_stack_item_t * stack = NULL; _LV_LL_READ_BACK(&manager->stack, stack) { if(stack->states == states) { was_top = stack_top == stack; void * stack_prev = _lv_ll_get_prev(&manager->stack, stack); if(!stack_prev) break; prev = ((lv_fragment_stack_item_t *) stack_prev)->states; break; } } if(stack) { _lv_ll_remove(&manager->stack, stack); } } item_del_obj(states); item_del_fragment(states); _lv_ll_remove(&manager->attached, states); if(prev && was_top) { item_create_obj(prev); } } void lv_fragment_manager_push(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container) { lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack); if(top != NULL) { item_del_obj(top->states); } lv_fragment_managed_states_t * states = fragment_attach(manager, fragment, container); states->in_stack = true; /*Add fragment to the top of the stack*/ lv_fragment_stack_item_t * item = _lv_ll_ins_tail(&manager->stack); lv_memset_00(item, sizeof(lv_fragment_stack_item_t)); item->states = states; item_create_obj(states); } bool lv_fragment_manager_pop(lv_fragment_manager_t * manager) { lv_fragment_t * top = lv_fragment_manager_get_top(manager); if(top == NULL) return false; lv_fragment_manager_remove(manager, top); return true; } void lv_fragment_manager_replace(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container) { lv_fragment_t * top = lv_fragment_manager_find_by_container(manager, *container); if(top != NULL) { lv_fragment_manager_remove(manager, top); } lv_fragment_manager_add(manager, fragment, container); } bool lv_fragment_manager_send_event(lv_fragment_manager_t * manager, int code, void * userdata) { LV_ASSERT_NULL(manager); lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack); if(!top) return false; lv_fragment_managed_states_t * states = top->states; lv_fragment_t * instance = states->instance; if(!instance) return false; if(lv_fragment_manager_send_event(instance->child_manager, code, userdata)) return true; if(!states->cls->event_cb) return false; return states->cls->event_cb(instance, code, userdata); } size_t lv_fragment_manager_get_stack_size(lv_fragment_manager_t * manager) { LV_ASSERT_NULL(manager); return _lv_ll_get_len(&manager->stack); } lv_fragment_t * lv_fragment_manager_get_top(lv_fragment_manager_t * manager) { LV_ASSERT(manager); lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack); if(!top)return NULL; return top->states->instance; } lv_fragment_t * lv_fragment_manager_find_by_container(lv_fragment_manager_t * manager, const lv_obj_t * container) { LV_ASSERT(manager); lv_fragment_managed_states_t * states; _LV_LL_READ(&manager->attached, states) { if(*states->container == container) return states->instance; } return NULL; } lv_fragment_t * lv_fragment_manager_get_parent_fragment(lv_fragment_manager_t * manager) { LV_ASSERT_NULL(manager); return manager->parent; } /********************** * STATIC FUNCTIONS **********************/ static void item_create_obj(lv_fragment_managed_states_t * item) { LV_ASSERT(item->instance); lv_fragment_create_obj(item->instance, item->container ? *item->container : NULL); } static void item_del_obj(lv_fragment_managed_states_t * item) { lv_fragment_del_obj(item->instance); } /** * Detach, then destroy fragment * @param item fragment states */ static void item_del_fragment(lv_fragment_managed_states_t * item) { lv_fragment_t * instance = item->instance; if(instance->cls->detached_cb) { instance->cls->detached_cb(instance); } instance->managed = NULL; lv_fragment_del(instance); item->instance = NULL; } static lv_fragment_managed_states_t * fragment_attach(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container) { LV_ASSERT(manager); LV_ASSERT(fragment); LV_ASSERT(fragment->managed == NULL); lv_fragment_managed_states_t * item = _lv_ll_ins_tail(&manager->attached); lv_memset_00(item, sizeof(lv_fragment_managed_states_t)); item->cls = fragment->cls; item->manager = manager; item->container = container; item->instance = fragment; fragment->managed = item; if(fragment->cls->attached_cb) { fragment->cls->attached_cb(fragment); } return item; } #endif /*LV_USE_FRAGMENT*/