1 /**
2  * @file lv_fragment_manager.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_fragment.h"
11 
12 #if LV_USE_FRAGMENT
13 
14 #include "../../../misc/lv_ll.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 
20 /**********************
21  *      TYPEDEFS
22  **********************/
23 typedef struct _lv_fragment_stack_item_t {
24     lv_fragment_managed_states_t * states;
25 } lv_fragment_stack_item_t;
26 
27 struct _lv_fragment_manager_t {
28     lv_fragment_t * parent;
29     /**
30      * Linked list to store attached fragments
31      */
32     lv_ll_t attached;
33     /**
34      * Linked list to store fragments in stack
35      */
36     lv_ll_t stack;
37 };
38 
39 /**********************
40  *  STATIC PROTOTYPES
41  **********************/
42 
43 static void item_create_obj(lv_fragment_managed_states_t * item);
44 
45 static void item_del_obj(lv_fragment_managed_states_t * item);
46 
47 static void item_del_fragment(lv_fragment_managed_states_t * item);
48 
49 static lv_fragment_managed_states_t * fragment_attach(lv_fragment_manager_t * manager, lv_fragment_t * fragment,
50                                                       lv_obj_t * const * container);
51 
52 /**********************
53  *  STATIC VARIABLES
54  **********************/
55 
56 /**********************
57  *      MACROS
58  **********************/
59 
60 /**********************
61  *   GLOBAL FUNCTIONS
62  **********************/
63 
lv_fragment_manager_create(lv_fragment_t * parent)64 lv_fragment_manager_t * lv_fragment_manager_create(lv_fragment_t * parent)
65 {
66     lv_fragment_manager_t * instance = lv_mem_alloc(sizeof(lv_fragment_manager_t));
67     lv_memset_00(instance, sizeof(lv_fragment_manager_t));
68     instance->parent = parent;
69     _lv_ll_init(&instance->attached, sizeof(lv_fragment_managed_states_t));
70     _lv_ll_init(&instance->stack, sizeof(lv_fragment_stack_item_t));
71     return instance;
72 }
73 
lv_fragment_manager_del(lv_fragment_manager_t * manager)74 void lv_fragment_manager_del(lv_fragment_manager_t * manager)
75 {
76     LV_ASSERT_NULL(manager);
77     lv_fragment_managed_states_t * states;
78     _LV_LL_READ_BACK(&manager->attached, states) {
79         item_del_obj(states);
80         item_del_fragment(states);
81     }
82     _lv_ll_clear(&manager->attached);
83     _lv_ll_clear(&manager->stack);
84     lv_mem_free(manager);
85 }
86 
lv_fragment_manager_create_obj(lv_fragment_manager_t * manager)87 void lv_fragment_manager_create_obj(lv_fragment_manager_t * manager)
88 {
89     LV_ASSERT_NULL(manager);
90     lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack);
91     lv_fragment_managed_states_t * states = NULL;
92     _LV_LL_READ(&manager->attached, states) {
93         if(states->in_stack && top->states != states) {
94             /*Only create obj for top item in stack*/
95             continue;
96         }
97         item_create_obj(states);
98     }
99 }
100 
lv_fragment_manager_del_obj(lv_fragment_manager_t * manager)101 void lv_fragment_manager_del_obj(lv_fragment_manager_t * manager)
102 {
103     LV_ASSERT_NULL(manager);
104     lv_fragment_managed_states_t * states = NULL;
105     _LV_LL_READ_BACK(&manager->attached, states) {
106         item_del_obj(states);
107     }
108 }
109 
lv_fragment_manager_add(lv_fragment_manager_t * manager,lv_fragment_t * fragment,lv_obj_t * const * container)110 void lv_fragment_manager_add(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container)
111 {
112     lv_fragment_managed_states_t * states = fragment_attach(manager, fragment, container);
113     if(!manager->parent || manager->parent->managed->obj_created) {
114         item_create_obj(states);
115     }
116 }
117 
lv_fragment_manager_remove(lv_fragment_manager_t * manager,lv_fragment_t * fragment)118 void lv_fragment_manager_remove(lv_fragment_manager_t * manager, lv_fragment_t * fragment)
119 {
120     LV_ASSERT_NULL(manager);
121     LV_ASSERT_NULL(fragment);
122     LV_ASSERT_NULL(fragment->managed);
123     LV_ASSERT(fragment->managed->manager == manager);
124     lv_fragment_managed_states_t * states = fragment->managed;
125     lv_fragment_managed_states_t * prev = NULL;
126     bool was_top = false;
127     if(states->in_stack) {
128         void * stack_top = _lv_ll_get_tail(&manager->stack);
129         lv_fragment_stack_item_t * item = NULL;
130         _LV_LL_READ_BACK(&manager->stack, item) {
131             if(item->states == states) {
132                 was_top = stack_top == item;
133                 void * stack_prev = _lv_ll_get_prev(&manager->stack, item);
134                 if(!stack_prev) break;
135                 prev = ((lv_fragment_stack_item_t *) stack_prev)->states;
136                 break;
137             }
138         }
139         if(item) {
140             _lv_ll_remove(&manager->stack, item);
141             lv_mem_free(item);
142         }
143     }
144     item_del_obj(states);
145     item_del_fragment(states);
146     _lv_ll_remove(&manager->attached, states);
147     lv_mem_free(states);
148     if(prev && was_top) {
149         item_create_obj(prev);
150     }
151 }
152 
lv_fragment_manager_push(lv_fragment_manager_t * manager,lv_fragment_t * fragment,lv_obj_t * const * container)153 void lv_fragment_manager_push(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container)
154 {
155     lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack);
156     if(top != NULL) {
157         item_del_obj(top->states);
158     }
159     lv_fragment_managed_states_t * states = fragment_attach(manager, fragment, container);
160     states->in_stack = true;
161     /*Add fragment to the top of the stack*/
162     lv_fragment_stack_item_t * item = _lv_ll_ins_tail(&manager->stack);
163     lv_memset_00(item, sizeof(lv_fragment_stack_item_t));
164     item->states = states;
165     item_create_obj(states);
166 }
167 
lv_fragment_manager_pop(lv_fragment_manager_t * manager)168 bool lv_fragment_manager_pop(lv_fragment_manager_t * manager)
169 {
170     lv_fragment_t * top = lv_fragment_manager_get_top(manager);
171     if(top == NULL) return false;
172     lv_fragment_manager_remove(manager, top);
173     return true;
174 }
175 
lv_fragment_manager_replace(lv_fragment_manager_t * manager,lv_fragment_t * fragment,lv_obj_t * const * container)176 void lv_fragment_manager_replace(lv_fragment_manager_t * manager, lv_fragment_t * fragment,
177                                  lv_obj_t * const * container)
178 {
179     lv_fragment_t * top = lv_fragment_manager_find_by_container(manager, *container);
180     if(top != NULL) {
181         lv_fragment_manager_remove(manager, top);
182     }
183     lv_fragment_manager_add(manager, fragment, container);
184 }
185 
lv_fragment_manager_send_event(lv_fragment_manager_t * manager,int code,void * userdata)186 bool lv_fragment_manager_send_event(lv_fragment_manager_t * manager, int code, void * userdata)
187 {
188     LV_ASSERT_NULL(manager);
189     lv_fragment_managed_states_t * p = NULL;
190     _LV_LL_READ_BACK(&manager->attached, p) {
191         if(!p->obj_created || p->destroying_obj) continue;
192         lv_fragment_t * instance = p->instance;
193         if(!instance) continue;
194         if(lv_fragment_manager_send_event(instance->child_manager, code, userdata)) return true;
195         if(p->cls->event_cb && p->cls->event_cb(instance, code, userdata)) return true;
196     }
197     return false;
198 }
199 
lv_fragment_manager_get_stack_size(lv_fragment_manager_t * manager)200 size_t lv_fragment_manager_get_stack_size(lv_fragment_manager_t * manager)
201 {
202     LV_ASSERT_NULL(manager);
203     return _lv_ll_get_len(&manager->stack);
204 }
205 
lv_fragment_manager_get_top(lv_fragment_manager_t * manager)206 lv_fragment_t * lv_fragment_manager_get_top(lv_fragment_manager_t * manager)
207 {
208     LV_ASSERT(manager);
209     lv_fragment_stack_item_t * top = _lv_ll_get_tail(&manager->stack);
210     if(!top)return NULL;
211     return top->states->instance;
212 }
213 
lv_fragment_manager_find_by_container(lv_fragment_manager_t * manager,const lv_obj_t * container)214 lv_fragment_t * lv_fragment_manager_find_by_container(lv_fragment_manager_t * manager, const lv_obj_t * container)
215 {
216     LV_ASSERT(manager);
217     lv_fragment_managed_states_t * states;
218     _LV_LL_READ(&manager->attached, states) {
219         if(*states->container == container) return states->instance;
220     }
221     return NULL;
222 }
223 
lv_fragment_manager_get_parent_fragment(lv_fragment_manager_t * manager)224 lv_fragment_t * lv_fragment_manager_get_parent_fragment(lv_fragment_manager_t * manager)
225 {
226     LV_ASSERT_NULL(manager);
227     return manager->parent;
228 }
229 
230 /**********************
231  *   STATIC FUNCTIONS
232  **********************/
233 
item_create_obj(lv_fragment_managed_states_t * item)234 static void item_create_obj(lv_fragment_managed_states_t * item)
235 {
236     LV_ASSERT(item->instance);
237     lv_fragment_create_obj(item->instance, item->container ? *item->container : NULL);
238 }
239 
item_del_obj(lv_fragment_managed_states_t * item)240 static void item_del_obj(lv_fragment_managed_states_t * item)
241 {
242     lv_fragment_del_obj(item->instance);
243 }
244 
245 /**
246  * Detach, then destroy fragment
247  * @param item fragment states
248  */
item_del_fragment(lv_fragment_managed_states_t * item)249 static void item_del_fragment(lv_fragment_managed_states_t * item)
250 {
251     lv_fragment_t * instance = item->instance;
252     if(instance->cls->detached_cb) {
253         instance->cls->detached_cb(instance);
254     }
255     instance->managed = NULL;
256     lv_fragment_del(instance);
257     item->instance = NULL;
258 }
259 
fragment_attach(lv_fragment_manager_t * manager,lv_fragment_t * fragment,lv_obj_t * const * container)260 static lv_fragment_managed_states_t * fragment_attach(lv_fragment_manager_t * manager, lv_fragment_t * fragment,
261                                                       lv_obj_t * const * container)
262 {
263     LV_ASSERT(manager);
264     LV_ASSERT(fragment);
265     LV_ASSERT(fragment->managed == NULL);
266     lv_fragment_managed_states_t * states = _lv_ll_ins_tail(&manager->attached);
267     lv_memset_00(states, sizeof(lv_fragment_managed_states_t));
268     states->cls = fragment->cls;
269     states->manager = manager;
270     states->container = container;
271     states->instance = fragment;
272     fragment->managed = states;
273     if(fragment->cls->attached_cb) {
274         fragment->cls->attached_cb(fragment);
275     }
276     return states;
277 }
278 
279 #endif /*LV_USE_FRAGMENT*/
280