summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaehyun Cho <jae_hyun.cho@samsung.com>2018-04-12 21:09:38 +0900
committerJaehyun Cho <jae_hyun.cho@samsung.com>2018-04-12 22:02:29 +0900
commit7fc81a4b66f57a00103cbc08aa0b6473f8c635e2 (patch)
tree4db1991e0197fa5301908d2f6df01c3a98d981d5
parent348bae4b24f216dbfa5118f92b7ebbc455e7018f (diff)
efl_ui_stack: Add Efl.Ui.Stack class
Efl.Ui.Stack is a container arranges objects in stack structure by pushing and popping them.
-rw-r--r--src/Makefile_Elementary.am3
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/efl_ui_stack.c972
-rw-r--r--src/lib/elementary/efl_ui_stack.eo131
-rw-r--r--src/lib/elementary/efl_ui_stack_private.h30
5 files changed, 1137 insertions, 0 deletions
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index 02008ee6e1..0751a36ec7 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -11,6 +11,7 @@ elm_public_eolian_files = \
11 lib/elementary/efl_ui_check.eo \ 11 lib/elementary/efl_ui_check.eo \
12 lib/elementary/efl_ui_flip.eo \ 12 lib/elementary/efl_ui_flip.eo \
13 lib/elementary/efl_ui_frame.eo \ 13 lib/elementary/efl_ui_frame.eo \
14 lib/elementary/efl_ui_stack.eo \
14 lib/elementary/efl_ui_image.eo \ 15 lib/elementary/efl_ui_image.eo \
15 lib/elementary/efl_ui_image_zoomable.eo \ 16 lib/elementary/efl_ui_image_zoomable.eo \
16 lib/elementary/efl_ui_layout.eo \ 17 lib/elementary/efl_ui_layout.eo \
@@ -327,6 +328,7 @@ includesunstable_HEADERS = \
327 lib/elementary/efl_ui_widget_flip.h \ 328 lib/elementary/efl_ui_widget_flip.h \
328 lib/elementary/elm_widget_flipselector.h \ 329 lib/elementary/elm_widget_flipselector.h \
329 lib/elementary/efl_ui_widget_frame.h \ 330 lib/elementary/efl_ui_widget_frame.h \
331 lib/elementary/efl_ui_stack_private.h \
330 lib/elementary/elm_widget_gengrid.h \ 332 lib/elementary/elm_widget_gengrid.h \
331 lib/elementary/elm_widget_genlist.h \ 333 lib/elementary/elm_widget_genlist.h \
332 lib/elementary/elm_widget_glview.h \ 334 lib/elementary/elm_widget_glview.h \
@@ -671,6 +673,7 @@ lib_elementary_libelementary_la_SOURCES = \
671 lib/elementary/elm_flipselector.c \ 673 lib/elementary/elm_flipselector.c \
672 lib/elementary/elm_font.c \ 674 lib/elementary/elm_font.c \
673 lib/elementary/efl_ui_frame.c \ 675 lib/elementary/efl_ui_frame.c \
676 lib/elementary/efl_ui_stack.c \
674 lib/elementary/elm_gengrid.c \ 677 lib/elementary/elm_gengrid.c \
675 lib/elementary/elm_genlist.c \ 678 lib/elementary/elm_genlist.c \
676 lib/elementary/elm_gesture_layer.c \ 679 lib/elementary/elm_gesture_layer.c \
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index a7161e4a9c..4099503810 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -336,6 +336,7 @@ typedef Eo Efl_Ui_Focus_Manager;
336# include <efl_selection.eo.h> 336# include <efl_selection.eo.h>
337# include <efl_ui_dnd.eo.h> 337# include <efl_ui_dnd.eo.h>
338# include <efl_ui_dnd_container.eo.h> 338# include <efl_ui_dnd_container.eo.h>
339# include <efl_ui_stack.eo.h>
339#endif 340#endif
340 341
341/* include deprecated calls last of all */ 342/* include deprecated calls last of all */
diff --git a/src/lib/elementary/efl_ui_stack.c b/src/lib/elementary/efl_ui_stack.c
new file mode 100644
index 0000000000..b827cc9766
--- /dev/null
+++ b/src/lib/elementary/efl_ui_stack.c
@@ -0,0 +1,972 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6
7#include "elm_priv.h"
8#include "efl_ui_stack_private.h"
9
10#define MY_CLASS EFL_UI_STACK_CLASS
11#define MY_CLASS_NAME "Efl.Ui.Stack"
12
13static Efl_Canvas_Animation *show_anim = NULL;
14static Efl_Canvas_Animation *hide_anim = NULL;
15
16static void
17_content_del_cb(void *data, const Efl_Event *event EINA_UNUSED)
18{
19 Content_Data *cd = data;
20
21 //Popped content has already called deactivated event and unloaded event.
22 if (cd->popped_hidden) return;
23
24 //Deactivated Event
25 Efl_Ui_Stack_Event_Deactivated deactivated_info;
26 deactivated_info.content = cd->content;
27 efl_event_callback_call(cd->stack,
28 EFL_UI_STACK_EVENT_DEACTIVATED,
29 &deactivated_info);
30
31 //Unloaded Event
32 Efl_Ui_Stack_Event_Unloaded unloaded_info;
33 unloaded_info.content = cd->content;
34 efl_event_callback_call(cd->stack,
35 EFL_UI_STACK_EVENT_UNLOADED,
36 &unloaded_info);
37}
38
39static Content_Data *
40_content_data_new(Eo *obj, Eo *content)
41{
42 Content_Data *cd = calloc(1, sizeof(Content_Data));
43 if (!cd)
44 {
45 ERR("Memory allocation error!");
46 return NULL;
47 }
48
49 cd->stack = obj;
50 cd->content = content;
51
52 efl_event_callback_add(cd->content, EFL_EVENT_DEL, _content_del_cb, cd);
53
54 return cd;
55}
56
57static void
58_content_data_del(Content_Data *cd)
59{
60 if (!cd) return;
61
62 if (cd->content)
63 efl_del(cd->content);
64
65 free(cd);
66}
67
68static void
69_anim_started_cb(void *data EINA_UNUSED, const Efl_Event *event)
70{
71 efl_canvas_object_freeze_events_set(event->object, EINA_TRUE);
72
73 efl_event_callback_del(event->object, EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
74 _anim_started_cb, NULL);
75}
76
77static void
78_anim_ended_cb(void *data, const Efl_Event *event)
79{
80 Transit_Data *td = data;
81 Efl_Canvas_Object_Animation_Event_Info *anim_event = event->info;
82
83 //Unset animation because originally there is no animation.
84 if (!td->orig_anim)
85 efl_canvas_object_event_animation_set(event->object,
86 anim_event->event_type, NULL);
87
88 efl_canvas_object_freeze_events_set(event->object,
89 td->freeze_events);
90
91 td->cd->on_pushing = EINA_FALSE;
92 td->cd->on_popping = EINA_FALSE;
93
94 if (anim_event->event_type == EFL_GFX_EVENT_SHOW)
95 {
96 //Activated Event
97 Efl_Ui_Stack_Event_Activated activated_info;
98 activated_info.content = event->object;
99 efl_event_callback_call(td->cd->stack,
100 EFL_UI_STACK_EVENT_ACTIVATED,
101 &activated_info);
102 }
103 else
104 {
105 //Deactivated Event
106 Efl_Ui_Stack_Event_Deactivated deactivated_info;
107 deactivated_info.content = event->object;
108 efl_event_callback_call(td->cd->stack,
109 EFL_UI_STACK_EVENT_DEACTIVATED,
110 &deactivated_info);
111
112 //Unloaded Event
113 Efl_Ui_Stack_Event_Unloaded unloaded_info;
114 unloaded_info.content = event->object;
115 efl_event_callback_call(td->cd->stack,
116 EFL_UI_STACK_EVENT_UNLOADED,
117 &unloaded_info);
118 }
119
120 efl_event_callback_del(event->object, EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
121 _anim_ended_cb, data);
122 free(data);
123}
124
125EOLIAN static void
126_efl_ui_stack_push(Eo *obj, Efl_Ui_Stack_Data *pd, Eo *content)
127{
128 if (!content) return;
129
130 //If the given content exists in the stack, promote the given content to the top.
131 Content_Data *cd = NULL;
132 EINA_INLIST_FOREACH(pd->stack, cd)
133 if (cd->content == content)
134 break;
135
136 Content_Data *top_cd = NULL;
137 if (pd->stack)
138 top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
139
140 if (cd)
141 {
142 //If given content is already the top content, then do nothing.
143 if (cd == top_cd)
144 return;
145
146 //Remove the given content(existing content) to promote it to the top.
147 pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
148 }
149 else
150 {
151 cd = _content_data_new(obj, content);
152 if (!cd) return;
153
154 evas_object_smart_member_add(content, obj);
155 }
156
157 pd->stack = eina_inlist_append(pd->stack, EINA_INLIST_GET(cd));
158
159 //Loaded Event
160 Efl_Ui_Stack_Event_Loaded loaded_info;
161 loaded_info.content = content;
162 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED, &loaded_info);
163
164 /* Apply transition to top content.
165 * Hide top content with animation. */
166 if (top_cd)
167 {
168 Eo *top_content = top_cd->content;
169
170 Efl_Canvas_Animation *orig_hide_anim =
171 efl_canvas_object_event_animation_get(top_content, EFL_GFX_EVENT_HIDE);
172
173 /* If content is being pushed now, then finish current animation and hide
174 * the content without animation. */
175 if (top_cd->on_pushing)
176 {
177 //Finish current animation.
178 efl_canvas_object_event_animation_set(top_content,
179 EFL_GFX_EVENT_SHOW, NULL);
180
181 //Hide without animation.
182 if (orig_hide_anim)
183 efl_canvas_object_event_animation_set(top_content,
184 EFL_GFX_EVENT_HIDE, NULL);
185
186 efl_gfx_visible_set(top_content, EINA_FALSE);
187
188 if (orig_hide_anim)
189 efl_canvas_object_event_animation_set(top_content,
190 EFL_GFX_EVENT_HIDE,
191 orig_hide_anim);
192
193 //Deactivated Event
194 Efl_Ui_Stack_Event_Deactivated deactivated_info;
195 deactivated_info.content = top_content;
196 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
197 &deactivated_info);
198
199 //Unloaded Event
200 Efl_Ui_Stack_Event_Unloaded unloaded_info;
201 unloaded_info.content = top_content;
202 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
203 &unloaded_info);
204 }
205 else
206 {
207 top_cd->on_pushing = EINA_TRUE;
208
209 //Hide with animation.
210 if (!orig_hide_anim)
211 efl_canvas_object_event_animation_set(top_content,
212 EFL_GFX_EVENT_HIDE,
213 hide_anim);
214
215 Transit_Data *td = calloc(1, sizeof(Transit_Data));
216 td->cd = top_cd;
217 td->orig_anim = !!(orig_hide_anim);
218 td->freeze_events = efl_canvas_object_freeze_events_get(top_content);
219
220 efl_event_callback_add(top_content,
221 EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
222 _anim_started_cb, NULL);
223 efl_event_callback_add(top_content,
224 EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
225 _anim_ended_cb, td);
226
227 efl_gfx_visible_set(top_content, EINA_FALSE);
228 }
229 }
230
231 /* Prepare transition for new content.
232 * Hide new content without animation. */
233 {
234 cd->on_pushing = EINA_TRUE;
235
236 Efl_Canvas_Animation *orig_hide_anim =
237 efl_canvas_object_event_animation_get(content, EFL_GFX_EVENT_HIDE);
238
239 //Hide without animation.
240 if (orig_hide_anim)
241 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_HIDE, NULL);
242 efl_gfx_visible_set(content, EINA_FALSE);
243
244 //Restore original hide animation
245 if (orig_hide_anim)
246 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_HIDE,
247 orig_hide_anim);
248 }
249
250 /* Apply transition to new content.
251 * Show new content with animation. */
252 {
253 evas_object_raise(content);
254
255 Efl_Canvas_Animation *orig_show_anim =
256 efl_canvas_object_event_animation_get(content, EFL_GFX_EVENT_SHOW);
257
258 //Show with animation
259 if (!orig_show_anim)
260 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
261 show_anim);
262
263 Transit_Data *td = calloc(1, sizeof(Transit_Data));
264 td->cd = cd;
265 td->orig_anim = !!(orig_show_anim);
266 td->freeze_events = efl_canvas_object_freeze_events_get(content);
267
268 efl_event_callback_add(content, EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
269 _anim_started_cb, NULL);
270 efl_event_callback_add(content, EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
271 _anim_ended_cb, td);
272
273 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
274 * internally.
275 * Therefore, efl_ui_widget_resize_object_set() is called after
276 * setting animation and efl_gfx_visible_set() is not called. */
277 efl_ui_widget_resize_object_set(obj, content);
278 }
279}
280
281static void
282_pop_content_hide_cb(void *data, const Efl_Event *event EINA_UNUSED)
283{
284 Content_Data *cd = data;
285
286 cd->popped_hidden = EINA_TRUE;
287
288 _content_data_del(cd);
289}
290
291EOLIAN static Eo *
292_efl_ui_stack_pop(Eo *obj, Efl_Ui_Stack_Data *pd)
293{
294 if (!pd->stack)
295 {
296 ERR("There is no content in the stack!");
297 return NULL;
298 }
299
300 Content_Data *top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
301 if (!top_cd) return NULL;
302
303 pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(top_cd));
304
305 /* Apply transition to top content.
306 * Hide top content with animation. */
307 {
308 Eo *top_content = top_cd->content;
309
310 Efl_Canvas_Animation *orig_hide_anim =
311 efl_canvas_object_event_animation_get(top_content, EFL_GFX_EVENT_HIDE);
312
313 /* If content is being popped now, then finish current animation and show
314 * the content without animation. */
315 if (top_cd->on_popping)
316 {
317 //Finish current animation.
318 efl_canvas_object_event_animation_set(top_content,
319 EFL_GFX_EVENT_SHOW, NULL);
320
321 //Hide without animation.
322 if (orig_hide_anim)
323 efl_canvas_object_event_animation_set(top_content,
324 EFL_GFX_EVENT_HIDE, NULL);
325
326 efl_gfx_visible_set(top_content, EINA_FALSE);
327
328 if (orig_hide_anim)
329 efl_canvas_object_event_animation_set(top_content,
330 EFL_GFX_EVENT_HIDE,
331 orig_hide_anim);
332
333 //Deactivated Event
334 Efl_Ui_Stack_Event_Deactivated deactivated_info;
335 deactivated_info.content = top_content;
336 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
337 &deactivated_info);
338
339 //Unloaded Event
340 Efl_Ui_Stack_Event_Unloaded unloaded_info;
341 unloaded_info.content = top_content;
342 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
343 &unloaded_info);
344
345 efl_canvas_object_event_animation_set(top_content,
346 EFL_GFX_EVENT_SHOW,
347 NULL);
348 }
349 else
350 {
351 top_cd->on_popping = EINA_TRUE;
352
353 //Hide with animation.
354 if (!orig_hide_anim)
355 efl_canvas_object_event_animation_set(top_content,
356 EFL_GFX_EVENT_HIDE,
357 hide_anim);
358
359 //Deallocate content data when hide animation is finished.
360 efl_event_callback_add(top_content, EFL_GFX_EVENT_HIDE,
361 _pop_content_hide_cb, top_cd);
362
363 Transit_Data *td = calloc(1, sizeof(Transit_Data));
364 td->cd = top_cd;
365 td->orig_anim = !!(orig_hide_anim);
366 td->freeze_events = efl_canvas_object_freeze_events_get(top_content);
367
368 efl_event_callback_add(top_content,
369 EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
370 _anim_started_cb, NULL);
371 efl_event_callback_add(top_content,
372 EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
373 _anim_ended_cb, td);
374
375 efl_gfx_visible_set(top_content, EINA_FALSE);
376 }
377 }
378
379 if (pd->stack)
380 {
381 Content_Data *prev_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last,
382 Content_Data);
383 if (prev_cd)
384 {
385 Eo *prev_content = prev_cd->content;
386
387 //If content is being pushed now, then finish current animation.
388 if (prev_cd->on_pushing)
389 {
390 efl_canvas_object_event_animation_set(prev_content,
391 EFL_GFX_EVENT_HIDE,
392 NULL);
393 }
394 prev_cd->on_popping = EINA_TRUE;
395
396 //Loaded Event
397 Efl_Ui_Stack_Event_Loaded loaded_info;
398 loaded_info.content = prev_content;
399 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
400 &loaded_info);
401
402 /* Apply transition to previous content.
403 * Show previous content with animation. */
404 {
405 Efl_Canvas_Animation *orig_show_anim =
406 efl_canvas_object_event_animation_get(prev_content,
407 EFL_GFX_EVENT_SHOW);
408
409 //Show with animation
410 if (!orig_show_anim)
411 efl_canvas_object_event_animation_set(prev_content,
412 EFL_GFX_EVENT_SHOW,
413 show_anim);
414
415 Transit_Data *td = calloc(1, sizeof(Transit_Data));
416 td->cd = prev_cd;
417 td->orig_anim = !!(orig_show_anim);
418 td->freeze_events =
419 efl_canvas_object_freeze_events_get(prev_content);
420
421 efl_event_callback_add(prev_content,
422 EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
423 _anim_started_cb, NULL);
424 efl_event_callback_add(prev_content,
425 EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
426 _anim_ended_cb, td);
427
428 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
429 * internally.
430 * Therefore, efl_ui_widget_resize_object_set() is called after
431 * setting animation and efl_gfx_visible_set() is not called. */
432 efl_ui_widget_resize_object_set(obj, prev_content);
433 }
434
435 }
436 }
437
438 return NULL;
439}
440
441EOLIAN static void
442_efl_ui_stack_insert_before(Eo *obj, Efl_Ui_Stack_Data *pd,
443 Eo *base_content, Eo *content)
444{
445 if (!content) return;
446
447 Content_Data *base_cd = NULL;
448 EINA_INLIST_FOREACH(pd->stack, base_cd)
449 if (base_cd->content == base_content)
450 break;
451
452 if (!base_cd)
453 {
454 ERR("The given base content is not found in the stack!");
455 return;
456 }
457
458 Content_Data *cd = _content_data_new(obj, content);
459 if (!cd) return;
460
461 pd->stack = eina_inlist_prepend_relative(pd->stack,
462 EINA_INLIST_GET(cd),
463 EINA_INLIST_GET(base_cd));
464 evas_object_smart_member_add(content, obj);
465}
466
467EOLIAN static void
468_efl_ui_stack_insert_after(Eo *obj, Efl_Ui_Stack_Data *pd,
469 Eo *base_content, Eo *content)
470{
471 if (!content) return;
472
473 Content_Data *base_cd = NULL;
474 EINA_INLIST_FOREACH(pd->stack, base_cd)
475 if (base_cd->content == base_content)
476 break;
477
478 if (!base_cd)
479 {
480 ERR("The given base content is not found in the stack!");
481 return;
482 }
483
484 Content_Data *cd = _content_data_new(obj, content);
485 if (!cd) return;
486
487 pd->stack = eina_inlist_append_relative(pd->stack,
488 EINA_INLIST_GET(cd),
489 EINA_INLIST_GET(base_cd));
490 evas_object_smart_member_add(content, obj);
491
492 if (pd->stack->last == EINA_INLIST_GET(cd))
493 {
494 //Loaded Event
495 Efl_Ui_Stack_Event_Loaded loaded_info;
496 loaded_info.content = content;
497 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
498 &loaded_info);
499
500 /* Do not apply transition for insert.
501 * Hide top content without animation. */
502 {
503 Efl_Canvas_Animation *orig_hide_anim =
504 efl_canvas_object_event_animation_get(base_cd->content,
505 EFL_GFX_EVENT_HIDE);
506
507 if (orig_hide_anim)
508 efl_canvas_object_event_animation_set(base_cd->content,
509 EFL_GFX_EVENT_HIDE, NULL);
510
511 efl_gfx_visible_set(base_cd->content, EINA_FALSE);
512
513 if (orig_hide_anim)
514 efl_canvas_object_event_animation_set(base_cd->content,
515 EFL_GFX_EVENT_HIDE,
516 orig_hide_anim);
517 }
518
519 //Deactivated Event
520 Efl_Ui_Stack_Event_Deactivated deactivated_info;
521 deactivated_info.content = base_cd->content;
522 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
523 &deactivated_info);
524
525 //Unloaded Event
526 Efl_Ui_Stack_Event_Unloaded unloaded_info;
527 unloaded_info.content = base_cd->content;
528 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
529 &unloaded_info);
530
531
532 /* Do not apply transition for insert.
533 * Show new content without animation. */
534 {
535 Efl_Canvas_Animation *orig_show_anim =
536 efl_canvas_object_event_animation_get(content,
537 EFL_GFX_EVENT_SHOW);
538
539 if (orig_show_anim)
540 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
541 NULL);
542
543 evas_object_raise(content);
544 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
545 * internally.
546 * Therefore, efl_ui_widget_resize_object_set() is called after
547 * setting animation and efl_gfx_visible_set() is not called. */
548 efl_ui_widget_resize_object_set(obj, content);
549
550 if (orig_show_anim)
551 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
552 orig_show_anim);
553 }
554
555 //Activated Event
556 Efl_Ui_Stack_Event_Activated activated_info;
557 activated_info.content = content;
558 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
559 &activated_info);
560 }
561}
562
563EOLIAN static void
564_efl_ui_stack_insert_at(Eo *obj, Efl_Ui_Stack_Data *pd,
565 int index, Eo *content)
566{
567 if (!content)
568 {
569 ERR("The given content is NULL!");
570 return;
571 }
572
573 int count = eina_inlist_count(pd->stack);
574 if ((index < 0) || (index > count))
575 {
576 ERR("The index(%d) should be from 0 to #contents in the stack(%d)!",
577 index, count);
578 return;
579 }
580
581 Content_Data *base_cd = NULL;
582
583 if (index == count)
584 {
585 base_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
586 }
587 else
588 {
589 int i = 0;
590 EINA_INLIST_FOREACH(pd->stack, base_cd)
591 {
592 if (i == index)
593 break;
594
595 i++;
596 }
597 }
598
599 Content_Data *cd = _content_data_new(obj, content);
600 if (!cd) return;
601
602 if (index == count)
603 pd->stack = eina_inlist_append_relative(pd->stack,
604 EINA_INLIST_GET(cd),
605 EINA_INLIST_GET(base_cd));
606 else
607 pd->stack = eina_inlist_prepend_relative(pd->stack,
608 EINA_INLIST_GET(cd),
609 EINA_INLIST_GET(base_cd));
610
611 evas_object_smart_member_add(content, obj);
612
613 if (pd->stack->last == EINA_INLIST_GET(cd))
614 {
615 //Loaded Event
616 Efl_Ui_Stack_Event_Loaded loaded_info;
617 loaded_info.content = content;
618 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
619 &loaded_info);
620
621 /* Do not apply transition for insert.
622 * Hide top content without animation. */
623 {
624 Efl_Canvas_Animation *orig_hide_anim =
625 efl_canvas_object_event_animation_get(base_cd->content,
626 EFL_GFX_EVENT_HIDE);
627
628 if (orig_hide_anim)
629 efl_canvas_object_event_animation_set(base_cd->content,
630 EFL_GFX_EVENT_HIDE, NULL);
631
632 efl_gfx_visible_set(base_cd->content, EINA_FALSE);
633
634 if (orig_hide_anim)
635 efl_canvas_object_event_animation_set(base_cd->content,
636 EFL_GFX_EVENT_HIDE,
637 orig_hide_anim);
638 }
639
640 //Deactivated Event
641 Efl_Ui_Stack_Event_Deactivated deactivated_info;
642 deactivated_info.content = base_cd->content;
643 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
644 &deactivated_info);
645
646 //Unloaded Event
647 Efl_Ui_Stack_Event_Unloaded unloaded_info;
648 unloaded_info.content = base_cd->content;
649 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
650 &unloaded_info);
651
652
653 /* Do not apply transition for insert.
654 * Show new content without animation. */
655 {
656 Efl_Canvas_Animation *orig_show_anim =
657 efl_canvas_object_event_animation_get(content,
658 EFL_GFX_EVENT_SHOW);
659
660 if (orig_show_anim)
661 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
662 NULL);
663
664 evas_object_raise(content);
665 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
666 * internally.
667 * Therefore, efl_ui_widget_resize_object_set() is called after
668 * setting animation and efl_gfx_visible_set() is not called. */
669 efl_ui_widget_resize_object_set(obj, content);
670
671 if (orig_show_anim)
672 efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
673 orig_show_anim);
674 }
675
676 //Activated Event
677 Efl_Ui_Stack_Event_Activated activated_info;
678 activated_info.content = content;
679 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
680 &activated_info);
681 }
682}
683
684EOLIAN static void
685_efl_ui_stack_remove(Eo *obj, Efl_Ui_Stack_Data *pd, Eo *content)
686{
687 if (!pd->stack)
688 {
689 ERR("There is no content in the stack!");
690 return;
691 }
692
693 if (!content)
694 {
695 ERR("The given content is NULL!");
696 return;
697 }
698
699 Content_Data *cd = NULL;
700
701 EINA_INLIST_FOREACH(pd->stack, cd)
702 {
703 if (cd->content == content)
704 break;
705 }
706 if (!cd)
707 {
708 ERR("The given content does not exist in the stack!");
709 return;
710 }
711
712 Eina_Bool remove_top = EINA_FALSE;
713 if (pd->stack->last == EINA_INLIST_GET(cd))
714 remove_top = EINA_TRUE;
715
716 pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
717
718 //Deactivated Event
719 Efl_Ui_Stack_Event_Deactivated deactivated_info;
720 deactivated_info.content = cd->content;
721 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
722 &deactivated_info);
723
724 //Unloaded Event
725 Efl_Ui_Stack_Event_Unloaded unloaded_info;
726 unloaded_info.content = cd->content;
727 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
728 &unloaded_info);
729 _content_data_del(cd);
730
731 if (remove_top)
732 {
733 if (pd->stack)
734 {
735 Content_Data *new_top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last,
736 Content_Data);
737 if (new_top_cd)
738 {
739 //Loaded Event
740 Efl_Ui_Stack_Event_Loaded loaded_info;
741 loaded_info.content = new_top_cd->content;
742 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
743 &loaded_info);
744
745 /* Do not apply transition for insert.
746 * Show new content without animation. */
747 {
748 Efl_Canvas_Animation *orig_show_anim =
749 efl_canvas_object_event_animation_get(new_top_cd->content,
750 EFL_GFX_EVENT_SHOW);
751
752 if (orig_show_anim)
753 efl_canvas_object_event_animation_set(new_top_cd->content,
754 EFL_GFX_EVENT_SHOW,
755 NULL);
756
757 evas_object_raise(new_top_cd->content);
758 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
759 * internally.
760 * Therefore, efl_ui_widget_resize_object_set() is called after
761 * setting animation and efl_gfx_visible_set() is not called. */
762 efl_ui_widget_resize_object_set(obj, new_top_cd->content);
763
764 if (orig_show_anim)
765 efl_canvas_object_event_animation_set(new_top_cd->content,
766 EFL_GFX_EVENT_SHOW,
767 orig_show_anim);
768 }
769
770 //Activated Event
771 Efl_Ui_Stack_Event_Activated activated_info;
772 activated_info.content = new_top_cd->content;
773 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
774 &activated_info);
775 }
776 }
777 }
778}
779
780EOLIAN static void
781_efl_ui_stack_remove_at(Eo *obj, Efl_Ui_Stack_Data *pd,
782 int index)
783{
784 if (!pd->stack)
785 {
786 ERR("There is no content in the stack!");
787 return;
788 }
789
790 int count = eina_inlist_count(pd->stack);
791 if ((index < 0) || (index >= count))
792 {
793 ERR("The index(%d) should be from 0 to (#contents - 1) in the stack(%d)!",
794 index, count);
795 return;
796 }
797
798 Content_Data *cd = NULL;
799 int i = 0;
800 EINA_INLIST_FOREACH(pd->stack, cd)
801 {
802 if (i == index)
803 break;
804 i++;
805 }
806
807 Eina_Bool remove_top = EINA_FALSE;
808 if (pd->stack->last == EINA_INLIST_GET(cd))
809 remove_top = EINA_TRUE;
810
811 pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
812
813 //Deactivated Event
814 Efl_Ui_Stack_Event_Deactivated deactivated_info;
815 deactivated_info.content = cd->content;
816 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
817 &deactivated_info);
818
819 //Unloaded Event
820 Efl_Ui_Stack_Event_Unloaded unloaded_info;
821 unloaded_info.content = cd->content;
822 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
823 &unloaded_info);
824 _content_data_del(cd);
825
826 //FIXME: Apply transition here.
827 if (remove_top)
828 {
829 if (pd->stack)
830 {
831 Content_Data *new_top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last,
832 Content_Data);
833 if (new_top_cd)
834 {
835 //Loaded Event
836 Efl_Ui_Stack_Event_Loaded loaded_info;
837 loaded_info.content = new_top_cd->content;
838 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
839 &loaded_info);
840
841 /* Do not apply transition for insert.
842 * Show new content without animation. */
843 {
844 Efl_Canvas_Animation *orig_show_anim =
845 efl_canvas_object_event_animation_get(new_top_cd->content,
846 EFL_GFX_EVENT_SHOW);
847
848 if (orig_show_anim)
849 efl_canvas_object_event_animation_set(new_top_cd->content,
850 EFL_GFX_EVENT_SHOW,
851 NULL);
852
853 evas_object_raise(new_top_cd->content);
854 /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
855 * internally.
856 * Therefore, efl_ui_widget_resize_object_set() is called after
857 * setting animation and efl_gfx_visible_set() is not called. */
858 efl_ui_widget_resize_object_set(obj, new_top_cd->content);
859
860 if (orig_show_anim)
861 efl_canvas_object_event_animation_set(new_top_cd->content,
862 EFL_GFX_EVENT_SHOW,
863 orig_show_anim);
864 }
865
866 //Activated Event
867 Efl_Ui_Stack_Event_Activated activated_info;
868 activated_info.content = new_top_cd->content;
869 efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
870 &activated_info);
871 }
872 }
873 }
874}
875
876EOLIAN static int
877_efl_ui_stack_index_get(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd, Efl_Canvas_Object *content)
878{
879 if (!pd->stack)
880 {
881 ERR("There is no content in the stack!");
882 return -1;
883 }
884
885 if (!content)
886 {
887 ERR("The given content is NULL!");
888 return -1;
889 }
890
891 Content_Data *cd = NULL;
892 int index = 0;
893 int count = eina_inlist_count(pd->stack);
894
895 EINA_INLIST_FOREACH(pd->stack, cd)
896 {
897 if (cd->content == content)
898 break;
899 index++;
900 }
901
902 //The given content is not found.
903 if (index == count) return -1;
904
905 return index;
906}
907
908EOLIAN static Eo *
909_efl_ui_stack_content_get(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd, int index)
910{
911 if (!pd->stack)
912 {
913 ERR("There is no content in the stack!");
914 return NULL;
915 }
916
917 int count = eina_inlist_count(pd->stack);
918 if ((index < 0) || (index >= count))
919 {
920 ERR("The index(%d) should be from 0 to (#contents - 1) in the stack(%d)!",
921 index, count);
922 return NULL;
923 }
924
925 Content_Data *cd = NULL;
926 int i = 0;
927 EINA_INLIST_FOREACH(pd->stack, cd)
928 {
929 if (i == index)
930 break;
931 i++;
932 }
933
934 if (cd)
935 return cd->content;
936
937 return NULL;
938}
939
940EOLIAN static Eo *
941_efl_ui_stack_top(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd)
942{
943 if (!pd->stack) return NULL;
944
945 Content_Data *cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
946 if (!cd) return NULL;
947
948 return cd->content;
949}
950
951EOLIAN static Eo *
952_efl_ui_stack_efl_object_constructor(Eo *obj, Efl_Ui_Stack_Data *pd EINA_UNUSED)
953{
954 obj = efl_constructor(efl_super(obj, MY_CLASS));
955 efl_canvas_object_type_set(obj, MY_CLASS_NAME);
956
957 //Default Show Animation
958 show_anim = efl_add(EFL_CANVAS_ANIMATION_ALPHA_CLASS, obj);
959 efl_animation_alpha_set(show_anim, 0.0, 1.0);
960 efl_animation_duration_set(show_anim, 0.5);
961 efl_animation_final_state_keep_set(show_anim, EINA_TRUE);
962
963 //Default Hide Animation
964 hide_anim = efl_add(EFL_CANVAS_ANIMATION_ALPHA_CLASS, obj);
965 efl_animation_alpha_set(hide_anim, 1.0, 0.0);
966 efl_animation_duration_set(hide_anim, 0.5);
967 efl_animation_final_state_keep_set(hide_anim, EINA_TRUE);
968
969 return obj;
970}
971
972#include "efl_ui_stack.eo.c"
diff --git a/src/lib/elementary/efl_ui_stack.eo b/src/lib/elementary/efl_ui_stack.eo
new file mode 100644
index 0000000000..2635e15588
--- /dev/null
+++ b/src/lib/elementary/efl_ui_stack.eo
@@ -0,0 +1,131 @@
1struct Efl.Ui.Stack.Event_Loaded {
2 [[Information of loaded event.]]
3 content: Efl.Canvas.Object; [[Loaded content.]]
4}
5
6struct Efl.Ui.Stack.Event_Unloaded {
7 [[Information of unloaded event.]]
8 content: Efl.Canvas.Object; [[Unloaded content.]]
9}
10
11struct Efl.Ui.Stack.Event_Activated {
12 [[Information of activated event.]]
13 content: Efl.Canvas.Object; [[Activated content.]]
14}
15
16struct Efl.Ui.Stack.Event_Deactivated {
17 [[Information of deactivated event.]]
18 content: Efl.Canvas.Object; [[Deactivated content.]]
19}
20
21class Efl.Ui.Stack (Efl.Ui.Layout)
22{
23 [[Stack widget.
24
25 Stack widget arranges objects in stack structure by pushing and poping them.
26 ]]
27 methods {
28 push {
29 [[Pushes a new object to the top of the stack and shows it.
30 ]]
31 params {
32 @in content: Efl.Canvas.Object;
33 [[The pushed object which becomes the top content of the stack.]]
34 }
35 }
36 pop {
37 [[Pops the top content from the stack and deletes it.
38 ]]
39 return: Efl.Canvas.Object;
40 [[The top content which is removed from the stack.]]
41 }
42 insert_before {
43 [[Inserts an object before the given base content in the stack.
44 ]]
45 params {
46 @in base_content: Efl.Canvas.Object;
47 [[$content is inserted before this $base_content.]]
48 @in content: Efl.Canvas.Object;
49 [[The inserted object in the stack.]]
50 }
51 }
52 insert_after {
53 [[Inserts an object after the given base content in the stack.
54 ]]
55 params {
56 @in base_content: Efl.Canvas.Object;
57 [[$content is inserted after this $base_content.]]
58 @in content: Efl.Canvas.Object;
59 [[The inserted object in the stack.]]
60 }
61 }
62 insert_at {
63 [[Inserts an object at the given place in the stack.
64 ]]
65 params {
66 @in index: int;
67 [[The index of the inserted object in the stack.
68 $index begins from bottom to top of the stack.
69 $index of the bottom content is 0.
70 ]]
71 @in content: Efl.Canvas.Object;
72 [[The inserted object in the stack.]]
73 }
74 }
75 remove {
76 [[Removes the given content in the stack.
77 ]]
78 params {
79 @in content: Efl.Canvas.Object;
80 [[The removed content from the stack.]]
81 }
82 }
83 remove_at {
84 [[Removes a content matched to the given index in the stack.
85 ]]
86 params {
87 @in index: int;
88 [[The index of the removed object in the stack.
89 $index begins from bottom to top of the stack.
90 $index of the bottom content is 0.
91 ]]
92 }
93 }
94 index_get {
95 [[Gets the index of the given content in the stack.
96 The index begins from bottom to top of the stack.
97 The index of the bottom content is 0.
98 ]]
99 return: int;
100 [[The index of $content in the stack.]]
101 params {
102 @in content: Efl.Canvas.Object;
103 [[The content matched to the index to be returned in the stack.]]
104 }
105 }
106 content_get {
107 [[Gets the content matched to the given index in the stack.
108 ]]
109 return: Efl.Canvas.Object;
110 [[The content matched to $index in the stack.]]
111 params {
112 @in index: int;
113 [[The index of the content to be returned in the stack.]]
114 }
115 }
116 top {
117 [[Gets the top content in the stack.
118 ]]
119 return: Efl.Canvas.Object; [[The top content in the stack.]]
120 }
121 }
122 implements {
123 Efl.Object.constructor;
124 }
125 events {
126 loaded; [[Called when content is loaded right before transition.]]
127 unloaded; [[Called when content is unloaded right after being deactivated.]]
128 activated; [[Called when content is activated right after transition.]]
129 deactivated; [[Called when content is deactivated right after transition.]]
130 }
131}
diff --git a/src/lib/elementary/efl_ui_stack_private.h b/src/lib/elementary/efl_ui_stack_private.h
new file mode 100644
index 0000000000..dc67451d58
--- /dev/null
+++ b/src/lib/elementary/efl_ui_stack_private.h
@@ -0,0 +1,30 @@
1#ifndef EFL_UI_WIDGET_STACK_H
2#define EFL_UI_WIDGET_STACK_H
3
4typedef struct _Efl_Ui_Stack_Data Efl_Ui_Stack_Data;
5struct _Efl_Ui_Stack_Data
6{
7 Eina_Inlist *stack; /* the last item is the top item */
8};
9
10typedef struct _Content_Data Content_Data;
11struct _Content_Data
12{
13 EINA_INLIST;
14
15 Eo *stack;
16 Eo *content;
17 Eina_Bool on_pushing : 1;
18 Eina_Bool on_popping : 1;
19 Eina_Bool popped_hidden : 1;
20};
21
22typedef struct _Transit_Data Transit_Data;
23struct _Transit_Data
24{
25 Content_Data *cd;
26 Eina_Bool orig_anim;
27 Eina_Bool freeze_events;
28};
29
30#endif