1 /**
2  * @file lv_fragment_manager.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_fragment_private.h"
11 
12 #if LV_USE_FRAGMENT
13 
14 #include "../../misc/lv_ll.h"
15 #include "../../stdlib/lv_string.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 typedef struct _lv_fragment_stack_item_t {
25     lv_fragment_managed_states_t * states;
26 } lv_fragment_stack_item_t;
27 
28 struct _lv_fragment_manager_t {
29     lv_fragment_t * parent;
30     /**
31      * Linked list to store attached fragments
32      */
33     lv_ll_t attached;
34     /**
35      * Linked list to store fragments in stack
36      */
37     lv_ll_t stack;
38 };
39 
40 /**********************
41  *  STATIC PROTOTYPES
42  **********************/
43 
44 static void item_create_obj(lv_fragment_managed_states_t * item);
45 
46 static void item_delete_obj(lv_fragment_managed_states_t * item);
47 
48 static void item_delete_fragment(lv_fragment_managed_states_t * item);
49 
50 static lv_fragment_managed_states_t * fragment_attach(lv_fragment_manager_t * manager, lv_fragment_t * fragment,
51                                                       lv_obj_t * const * container);
52 
53 /**********************
54  *  STATIC VARIABLES
55  **********************/
56 
57 /**********************
58  *      MACROS
59  **********************/
60 
61 /**********************
62  *   GLOBAL FUNCTIONS
63  **********************/
64 
lv_fragment_manager_create(lv_fragment_t * parent)65 lv_fragment_manager_t * lv_fragment_manager_create(lv_fragment_t * parent)
66 {
67     lv_fragment_manager_t * instance = lv_malloc_zeroed(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_delete(lv_fragment_manager_t * manager)74 void lv_fragment_manager_delete(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_delete_obj(states);
80         item_delete_fragment(states);
81     }
82     lv_ll_clear(&manager->attached);
83     lv_ll_clear(&manager->stack);
84     lv_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_delete_obj(lv_fragment_manager_t * manager)101 void lv_fragment_manager_delete_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_delete_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_free(item);
142         }
143     }
144     item_delete_obj(states);
145     item_delete_fragment(states);
146     lv_ll_remove(&manager->attached, states);
147     lv_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_delete_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_memzero(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_delete_obj(lv_fragment_managed_states_t * item)240 static void item_delete_obj(lv_fragment_managed_states_t * item)
241 {
242     lv_fragment_delete_obj(item->instance);
243 }
244 
245 /**
246  * Detach, then destroy fragment
247  * @param item fragment states
248  */
item_delete_fragment(lv_fragment_managed_states_t * item)249 static void item_delete_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_delete(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_memzero(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