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