feat(fragment): add fragment manager (a UI Controller concept) (#2940)
* adding lv_obj_controller * adding examples for lv_obj_controller * added some docs * formatted code * updated controller docs * updated controller docs * updated sample controller field * changed lv_controller_manager_parent to lv_controller_manager_get_parent * updated unmanaged controller creation/deletion * renamed lv_controller_manager_t * rename: controller -> fragment * formatted code * Update examples/others/fragment/lv_example_fragment.h Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> * Update src/extra/others/fragment/lv_fragment.c Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> * Update src/extra/others/fragment/lv_fragment.c Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> * Update src/extra/others/fragment/lv_fragment.c Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> * code cleanup * fragment creation rework * (wip) fragment manager * (wip) fragment manager * refactoring fragment * lifecycle fixes * updated fragment event callback * exposed states of fragment * added some docs * updated lv_fragment_managed_states_t name * updated docs * updated docs * updated lv_fragment_manager_dispatch_event docs * removed msgbox fragment * updated fragment docs * updated fragment docs * updated docs * updating examples * fixed example * reformatted code * fixed obj_created set timing * simplified fragment * improved fragment view del assertion * fixed a typo * fixed event_cb check in lv_obj_remove_event_cb_with_user_data * fixing fragment obj assertion * regenerated config * fixed fragment examples * fixed fragment examples * added missing examples * updated docs * fragment api cleanup * rename fragment struct names * added missing param doc * enabled test for 32bit build * feat(porting): add a macro lv_run_timer_handler_in_period to simplify porting (#3063) * feat(porting): add a macro lv_run_timer_handler_in_period to simplify porting * feat: update helper function and doc * doc(porting): update function names * revise to the original os.md * fix: fix typo * fix: mitigate warnings * chore: fix code formatting * fix(fsdrv): replacing sprintf with lv_snprintf for safety (#3079) * fix(Kconfig) remove duplicate LV_BUILD_EXAMPLES configuration * feat(refr) add reset of FPS statistics * fix(conf) mismatched macro judgment * feat(fsdrv) replacing sprintf with lv_snprintf for safety * feat(fsdrv) update stdio and win32 Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com> * fix warnings Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> Co-authored-by: Gabriel Wang <embedded_zhuoran@Hotmail.com> Co-authored-by: _VIFEXTech <1290176185@qq.com> Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
0
src/extra/others/fragment/README.md
Normal file
0
src/extra/others/fragment/README.md
Normal file
137
src/extra/others/fragment/lv_fragment.c
Normal file
137
src/extra/others/fragment/lv_fragment.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @file lv_fragment.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_fragment.h"
|
||||
|
||||
#if LV_USE_FRAGMENT
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void cb_delete_assertion(lv_event_t * event);
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_fragment_t * lv_fragment_create(const lv_fragment_class_t * cls, void * args)
|
||||
{
|
||||
LV_ASSERT_NULL(cls);
|
||||
LV_ASSERT_NULL(cls->create_obj_cb);
|
||||
LV_ASSERT(cls->instance_size > 0);
|
||||
lv_fragment_t * instance = lv_mem_alloc(cls->instance_size);
|
||||
lv_memset_00(instance, cls->instance_size);
|
||||
instance->cls = cls;
|
||||
instance->child_manager = lv_fragment_manager_create(instance);
|
||||
if(cls->constructor_cb) {
|
||||
cls->constructor_cb(instance, args);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void lv_fragment_del(lv_fragment_t * fragment)
|
||||
{
|
||||
LV_ASSERT_NULL(fragment);
|
||||
if(fragment->managed) {
|
||||
lv_fragment_manager_remove(fragment->managed->manager, fragment);
|
||||
return;
|
||||
}
|
||||
if(fragment->obj) {
|
||||
lv_fragment_del_obj(fragment);
|
||||
}
|
||||
/* Objects will leak if this function called before objects deleted */
|
||||
const lv_fragment_class_t * cls = fragment->cls;
|
||||
if(cls->destructor_cb) {
|
||||
cls->destructor_cb(fragment);
|
||||
}
|
||||
lv_fragment_manager_del(fragment->child_manager);
|
||||
lv_mem_free(fragment);
|
||||
}
|
||||
|
||||
lv_obj_t * const * lv_fragment_get_container(lv_fragment_t * fragment)
|
||||
{
|
||||
LV_ASSERT_NULL(fragment);
|
||||
LV_ASSERT_NULL(fragment->managed);
|
||||
return fragment->managed->container;
|
||||
}
|
||||
|
||||
lv_fragment_t * lv_fragment_get_parent(lv_fragment_t * fragment)
|
||||
{
|
||||
LV_ASSERT_NULL(fragment);
|
||||
LV_ASSERT_NULL(fragment->managed);
|
||||
return lv_fragment_manager_get_parent_fragment(fragment->managed->manager);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_fragment_create_obj(lv_fragment_t * fragment, lv_obj_t * container)
|
||||
{
|
||||
lv_fragment_managed_states_t * states = fragment->managed;
|
||||
if(states) {
|
||||
states->destroying_obj = false;
|
||||
}
|
||||
const lv_fragment_class_t * cls = fragment->cls;
|
||||
lv_obj_t * obj = cls->create_obj_cb(fragment, container);
|
||||
LV_ASSERT_NULL(obj);
|
||||
fragment->obj = obj;
|
||||
lv_fragment_manager_create_obj(fragment->child_manager);
|
||||
if(states) {
|
||||
states->obj_created = true;
|
||||
lv_obj_add_event_cb(obj, cb_delete_assertion, LV_EVENT_DELETE, NULL);
|
||||
}
|
||||
if(cls->obj_created_cb) {
|
||||
cls->obj_created_cb(fragment, obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void lv_fragment_del_obj(lv_fragment_t * fragment)
|
||||
{
|
||||
LV_ASSERT_NULL(fragment);
|
||||
lv_fragment_manager_del_obj(fragment->child_manager);
|
||||
lv_fragment_managed_states_t * states = fragment->managed;
|
||||
if(states) {
|
||||
if(!states->obj_created) return;
|
||||
states->destroying_obj = true;
|
||||
bool cb_removed = lv_obj_remove_event_cb(fragment->obj, cb_delete_assertion);
|
||||
LV_ASSERT(cb_removed);
|
||||
}
|
||||
LV_ASSERT_NULL(fragment->obj);
|
||||
const lv_fragment_class_t * cls = fragment->cls;
|
||||
if(cls->obj_will_delete_cb) {
|
||||
cls->obj_will_delete_cb(fragment, fragment->obj);
|
||||
}
|
||||
lv_obj_del(fragment->obj);
|
||||
if(cls->obj_deleted_cb) {
|
||||
cls->obj_deleted_cb(fragment, fragment->obj);
|
||||
}
|
||||
if(states) {
|
||||
states->obj_created = false;
|
||||
}
|
||||
fragment->obj = NULL;
|
||||
}
|
||||
|
||||
void lv_fragment_recreate_obj(lv_fragment_t * fragment)
|
||||
{
|
||||
LV_ASSERT_NULL(fragment);
|
||||
LV_ASSERT_NULL(fragment->managed);
|
||||
lv_fragment_del_obj(fragment);
|
||||
lv_fragment_create_obj(fragment, *fragment->managed->container);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void cb_delete_assertion(lv_event_t * event)
|
||||
{
|
||||
LV_UNUSED(event);
|
||||
LV_ASSERT_MSG(0, "Please delete objects with lv_fragment_destroy_obj");
|
||||
}
|
||||
|
||||
#endif /*LV_USE_FRAGMENT*/
|
||||
339
src/extra/others/fragment/lv_fragment.h
Normal file
339
src/extra/others/fragment/lv_fragment.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* Public header for Fragment
|
||||
* @file lv_fragment.h
|
||||
*/
|
||||
|
||||
#ifndef LV_FRAGMENT_H
|
||||
#define LV_FRAGMENT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_FRAGMENT
|
||||
|
||||
#include "../../../core/lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct _lv_fragment_manager_t lv_fragment_manager_t;
|
||||
|
||||
typedef struct _lv_fragment_t lv_fragment_t;
|
||||
typedef struct _lv_fragment_class_t lv_fragment_class_t;
|
||||
typedef struct _lv_fragment_managed_states_t lv_fragment_managed_states_t;
|
||||
|
||||
struct _lv_fragment_t {
|
||||
/**
|
||||
* Class of this fragment
|
||||
*/
|
||||
const lv_fragment_class_t * cls;
|
||||
/**
|
||||
* Managed fragment states. If not null, then this fragment is managed.
|
||||
*
|
||||
* @warning Don't modify values inside this struct!
|
||||
*/
|
||||
lv_fragment_managed_states_t * managed;
|
||||
/**
|
||||
* Child fragment manager
|
||||
*/
|
||||
lv_fragment_manager_t * child_manager;
|
||||
/**
|
||||
* lv_obj returned by create_obj_cb
|
||||
*/
|
||||
lv_obj_t * obj;
|
||||
|
||||
};
|
||||
|
||||
struct _lv_fragment_class_t {
|
||||
/**
|
||||
* Constructor function for fragment class
|
||||
* @param self Fragment instance
|
||||
* @param args Arguments assigned by fragment manager
|
||||
*/
|
||||
void (*constructor_cb)(lv_fragment_t * self, void * args);
|
||||
|
||||
/**
|
||||
* Destructor function for fragment class
|
||||
* @param self Fragment instance, will be freed after this call
|
||||
*/
|
||||
void (*destructor_cb)(lv_fragment_t * self);
|
||||
|
||||
/**
|
||||
* Fragment attached to manager
|
||||
* @param self Fragment instance
|
||||
*/
|
||||
void (*attached_cb)(lv_fragment_t * self);
|
||||
|
||||
/**
|
||||
* Fragment detached from manager
|
||||
* @param self Fragment instance
|
||||
*/
|
||||
void (*detached_cb)(lv_fragment_t * self);
|
||||
|
||||
/**
|
||||
* Create objects
|
||||
* @param self Fragment instance
|
||||
* @param container Container of the objects should be created upon
|
||||
* @return Created object, NULL if multiple objects has been created
|
||||
*/
|
||||
lv_obj_t * (*create_obj_cb)(lv_fragment_t * self, lv_obj_t * container);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param self Fragment instance
|
||||
* @param obj lv_obj returned by create_obj_cb
|
||||
*/
|
||||
void (*obj_created_cb)(lv_fragment_t * self, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Called before objects in the fragment will be deleted.
|
||||
*
|
||||
* @param self Fragment instance
|
||||
* @param obj object with this fragment
|
||||
*/
|
||||
void (*obj_will_delete_cb)(lv_fragment_t * self, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Called when the object created by fragment received `LV_EVENT_DELETE` event
|
||||
* @param self Fragment instance
|
||||
* @param obj object with this fragment
|
||||
*/
|
||||
void (*obj_deleted_cb)(lv_fragment_t * self, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Handle event
|
||||
* @param self Fragment instance
|
||||
* @param which User-defined ID of event
|
||||
* @param data1 User-defined data
|
||||
* @param data2 User-defined data
|
||||
*/
|
||||
bool (*event_cb)(lv_fragment_t * self, int code, void * userdata);
|
||||
|
||||
/**
|
||||
* *REQUIRED*: Allocation size of fragment
|
||||
*/
|
||||
size_t instance_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fragment states
|
||||
*/
|
||||
typedef struct _lv_fragment_managed_states_t {
|
||||
/**
|
||||
* Class of the fragment
|
||||
*/
|
||||
const lv_fragment_class_t * cls;
|
||||
/**
|
||||
* Manager the fragment attached to
|
||||
*/
|
||||
lv_fragment_manager_t * manager;
|
||||
/**
|
||||
* Container object the fragment adding view to
|
||||
*/
|
||||
lv_obj_t * const * container;
|
||||
/**
|
||||
* Fragment instance
|
||||
*/
|
||||
lv_fragment_t * instance;
|
||||
/**
|
||||
* true between `create_obj_cb` and `obj_deleted_cb`
|
||||
*/
|
||||
bool obj_created;
|
||||
/**
|
||||
* true before `lv_fragment_del_obj` is called. Don't touch any object if this is true
|
||||
*/
|
||||
bool destroying_obj;
|
||||
/**
|
||||
* true if this fragment is in navigation stack that can be popped
|
||||
*/
|
||||
bool in_stack;
|
||||
} lv_fragment_managed_states_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create fragment manager instance
|
||||
* @param parent Parent fragment if this manager is placed inside another fragment, can be null.
|
||||
* @return Fragment manager instance
|
||||
*/
|
||||
lv_fragment_manager_t * lv_fragment_manager_create(lv_fragment_t * parent);
|
||||
|
||||
/**
|
||||
* Destroy fragment manager instance
|
||||
* @param manager Fragment manager instance
|
||||
*/
|
||||
void lv_fragment_manager_del(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Create object of all fragments managed by this manager.
|
||||
* @param manager Fragment manager instance
|
||||
*/
|
||||
void lv_fragment_manager_create_obj(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Delete object created by all fragments managed by this manager. Instance of fragments will not be deleted.
|
||||
* @param manager Fragment manager instance
|
||||
*/
|
||||
void lv_fragment_manager_del_obj(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Attach fragment to manager, and add to container.
|
||||
* @param manager Fragment manager instance
|
||||
* @param fragment Fragment instance
|
||||
* @param container Pointer to container object for manager to add objects to
|
||||
*/
|
||||
void lv_fragment_manager_add(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container);
|
||||
|
||||
/**
|
||||
* Detach and destroy fragment. If fragment is in navigation stack, remove from it.
|
||||
* @param manager Fragment manager instance
|
||||
* @param fragment Fragment instance
|
||||
*/
|
||||
void lv_fragment_manager_remove(lv_fragment_manager_t * manager, lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Attach fragment to manager and add to navigation stack.
|
||||
* @param manager Fragment manager instance
|
||||
* @param fragment Fragment instance
|
||||
* @param container Pointer to container object for manager to add objects to
|
||||
*/
|
||||
void lv_fragment_manager_push(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container);
|
||||
|
||||
/**
|
||||
* Remove the top-most fragment for stack
|
||||
* @param manager Fragment manager instance
|
||||
* @return true if there is fragment to pop
|
||||
*/
|
||||
bool lv_fragment_manager_pop(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Replace fragment. Old item in the stack will be removed.
|
||||
* @param manager Fragment manager instance
|
||||
* @param fragment Fragment instance
|
||||
* @param container Pointer to container object for manager to add objects to
|
||||
*/
|
||||
void lv_fragment_manager_replace(lv_fragment_manager_t * manager, lv_fragment_t * fragment,
|
||||
lv_obj_t * const * container);
|
||||
|
||||
/**
|
||||
* Send event to top-most fragment
|
||||
* @param manager Fragment manager instance
|
||||
* @param code User-defined ID of event
|
||||
* @param userdata User-defined data
|
||||
* @return true if fragment returned true
|
||||
*/
|
||||
bool lv_fragment_manager_send_event(lv_fragment_manager_t * manager, int code, void * userdata);
|
||||
|
||||
/**
|
||||
* Get stack size of this fragment manager
|
||||
* @param manager Fragment manager instance
|
||||
* @return Stack size of this fragment manager
|
||||
*/
|
||||
size_t lv_fragment_manager_get_stack_size(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Get top most fragment instance
|
||||
* @param manager Fragment manager instance
|
||||
* @return Top most fragment instance
|
||||
*/
|
||||
lv_fragment_t * lv_fragment_manager_get_top(lv_fragment_manager_t * manager);
|
||||
|
||||
/**
|
||||
* Find first fragment instance in the container
|
||||
* @param manager Fragment manager instance
|
||||
* @param container Container which target fragment added to
|
||||
* @return First fragment instance in the container
|
||||
*/
|
||||
lv_fragment_t * lv_fragment_manager_find_by_container(lv_fragment_manager_t * manager, const lv_obj_t * container);
|
||||
|
||||
/**
|
||||
* Get parent fragment
|
||||
* @param manager Fragment manager instance
|
||||
* @return Parent fragment instance
|
||||
*/
|
||||
lv_fragment_t * lv_fragment_manager_get_parent_fragment(lv_fragment_manager_t * manager);
|
||||
|
||||
|
||||
/**
|
||||
* Create a fragment instance.
|
||||
*
|
||||
* @param cls Fragment class. This fragment must return non null object.
|
||||
* @param args Arguments assigned by fragment manager
|
||||
* @return Fragment instance
|
||||
*/
|
||||
lv_fragment_t * lv_fragment_create(const lv_fragment_class_t * cls, void * args);
|
||||
|
||||
/**
|
||||
* Destroy a fragment.
|
||||
* @param fragment Fragment instance.
|
||||
*/
|
||||
void lv_fragment_del(lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Get associated manager of this fragment
|
||||
* @param fragment Fragment instance
|
||||
* @return Fragment manager instance
|
||||
*/
|
||||
lv_fragment_manager_t * lv_fragment_get_manager(lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Get container object of this fragment
|
||||
* @param fragment Fragment instance
|
||||
* @return Reference to container object
|
||||
*/
|
||||
lv_obj_t * const * lv_fragment_get_container(lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Get parent fragment of this fragment
|
||||
* @param fragment Fragment instance
|
||||
* @return Parent fragment
|
||||
*/
|
||||
lv_fragment_t * lv_fragment_get_parent(lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Create object by fragment.
|
||||
*
|
||||
* @param fragment Fragment instance.
|
||||
* @param container Container of the objects should be created upon.
|
||||
* @return Created object
|
||||
*/
|
||||
lv_obj_t * lv_fragment_create_obj(lv_fragment_t * fragment, lv_obj_t * container);
|
||||
|
||||
/**
|
||||
* Delete created object of a fragment
|
||||
*
|
||||
* @param fragment Fragment instance.
|
||||
*/
|
||||
void lv_fragment_del_obj(lv_fragment_t * fragment);
|
||||
|
||||
/**
|
||||
* Destroy obj in fragment, and recreate them.
|
||||
* @param fragment Fragment instance
|
||||
*/
|
||||
void lv_fragment_recreate_obj(lv_fragment_t * fragment);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_FRAGMENT*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_FRAGMENT_H*/
|
||||
278
src/extra/others/fragment/lv_fragment_manager.c
Normal file
278
src/extra/others/fragment/lv_fragment_manager.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* @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*/
|
||||
@@ -16,6 +16,7 @@ extern "C" {
|
||||
#include "snapshot/lv_snapshot.h"
|
||||
#include "monkey/lv_monkey.h"
|
||||
#include "gridnav/lv_gridnav.h"
|
||||
#include "fragment/lv_fragment.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
||||
Reference in New Issue
Block a user