jaehyun pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=ab4fa83f62ea8f23e137bd6f245502c5c6cdaaa0

commit ab4fa83f62ea8f23e137bd6f245502c5c6cdaaa0
Author: Jaehyun Cho <[email protected]>
Date:   Thu Apr 12 21:09:38 2018 +0900

    efl_ui_stack: Add Efl.Ui.Stack class
    
    Efl.Ui.Stack is a container arranges objects in stack structure by
    pushing and popping them.
---
 src/Makefile_Elementary.am                |   3 +
 src/lib/elementary/Elementary.h           |   1 +
 src/lib/elementary/efl_ui_stack.c         | 972 ++++++++++++++++++++++++++++++
 src/lib/elementary/efl_ui_stack.eo        | 131 ++++
 src/lib/elementary/efl_ui_stack_private.h |  30 +
 5 files changed, 1137 insertions(+)

diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index 0ae0a2d21b..a9e1dc252b 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -11,6 +11,7 @@ elm_public_eolian_files = \
        lib/elementary/efl_ui_check.eo \
        lib/elementary/efl_ui_flip.eo \
        lib/elementary/efl_ui_frame.eo \
+       lib/elementary/efl_ui_stack.eo \
        lib/elementary/efl_ui_image.eo \
        lib/elementary/efl_ui_image_zoomable.eo \
        lib/elementary/efl_ui_layout.eo \
@@ -326,6 +327,7 @@ includesunstable_HEADERS = \
        lib/elementary/efl_ui_widget_flip.h \
        lib/elementary/elm_widget_flipselector.h \
        lib/elementary/efl_ui_widget_frame.h \
+       lib/elementary/efl_ui_stack_private.h \
        lib/elementary/elm_widget_gengrid.h \
        lib/elementary/elm_widget_genlist.h \
        lib/elementary/elm_widget_glview.h \
@@ -668,6 +670,7 @@ lib_elementary_libelementary_la_SOURCES = \
        lib/elementary/elm_flipselector.c \
        lib/elementary/elm_font.c \
        lib/elementary/efl_ui_frame.c \
+       lib/elementary/efl_ui_stack.c \
        lib/elementary/elm_gengrid.c \
        lib/elementary/elm_genlist.c \
        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;
 # include <efl_selection.eo.h>
 # include <efl_ui_dnd.eo.h>
 # include <efl_ui_dnd_container.eo.h>
+# include <efl_ui_stack.eo.h>
 #endif
 
 /* 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 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+
+#include "elm_priv.h"
+#include "efl_ui_stack_private.h"
+
+#define MY_CLASS EFL_UI_STACK_CLASS
+#define MY_CLASS_NAME "Efl.Ui.Stack"
+
+static Efl_Canvas_Animation *show_anim = NULL;
+static Efl_Canvas_Animation *hide_anim = NULL;
+
+static void
+_content_del_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+   Content_Data *cd = data;
+
+   //Popped content has already called deactivated event and unloaded event.
+   if (cd->popped_hidden) return;
+
+   //Deactivated Event
+   Efl_Ui_Stack_Event_Deactivated deactivated_info;
+   deactivated_info.content = cd->content;
+   efl_event_callback_call(cd->stack,
+                           EFL_UI_STACK_EVENT_DEACTIVATED,
+                           &deactivated_info);
+
+   //Unloaded Event
+   Efl_Ui_Stack_Event_Unloaded unloaded_info;
+   unloaded_info.content = cd->content;
+   efl_event_callback_call(cd->stack,
+                           EFL_UI_STACK_EVENT_UNLOADED,
+                           &unloaded_info);
+}
+
+static Content_Data *
+_content_data_new(Eo *obj, Eo *content)
+{
+   Content_Data *cd = calloc(1, sizeof(Content_Data));
+   if (!cd)
+     {
+        ERR("Memory allocation error!");
+        return NULL;
+     }
+
+   cd->stack = obj;
+   cd->content = content;
+
+   efl_event_callback_add(cd->content, EFL_EVENT_DEL, _content_del_cb, cd);
+
+   return cd;
+}
+
+static void
+_content_data_del(Content_Data *cd)
+{
+   if (!cd) return;
+
+   if (cd->content)
+     efl_del(cd->content);
+
+   free(cd);
+}
+
+static void
+_anim_started_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   efl_canvas_object_freeze_events_set(event->object, EINA_TRUE);
+
+   efl_event_callback_del(event->object, EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
+                          _anim_started_cb, NULL);
+}
+
+static void
+_anim_ended_cb(void *data, const Efl_Event *event)
+{
+   Transit_Data *td = data;
+   Efl_Canvas_Object_Animation_Event_Info *anim_event = event->info;
+
+   //Unset animation because originally there is no animation.
+   if (!td->orig_anim)
+     efl_canvas_object_event_animation_set(event->object,
+                                           anim_event->event_type, NULL);
+
+   efl_canvas_object_freeze_events_set(event->object,
+                                       td->freeze_events);
+
+   td->cd->on_pushing = EINA_FALSE;
+   td->cd->on_popping = EINA_FALSE;
+
+   if (anim_event->event_type == EFL_GFX_EVENT_SHOW)
+     {
+        //Activated Event
+        Efl_Ui_Stack_Event_Activated activated_info;
+        activated_info.content = event->object;
+        efl_event_callback_call(td->cd->stack,
+                                EFL_UI_STACK_EVENT_ACTIVATED,
+                                &activated_info);
+     }
+   else
+     {
+        //Deactivated Event
+        Efl_Ui_Stack_Event_Deactivated deactivated_info;
+        deactivated_info.content = event->object;
+        efl_event_callback_call(td->cd->stack,
+                                EFL_UI_STACK_EVENT_DEACTIVATED,
+                                &deactivated_info);
+
+        //Unloaded Event
+        Efl_Ui_Stack_Event_Unloaded unloaded_info;
+        unloaded_info.content = event->object;
+        efl_event_callback_call(td->cd->stack,
+                                EFL_UI_STACK_EVENT_UNLOADED,
+                                &unloaded_info);
+     }
+
+   efl_event_callback_del(event->object, EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
+                          _anim_ended_cb, data);
+   free(data);
+}
+
+EOLIAN static void
+_efl_ui_stack_push(Eo *obj, Efl_Ui_Stack_Data *pd, Eo *content)
+{
+   if (!content) return;
+
+   //If the given content exists in the stack, promote the given content to 
the top.
+   Content_Data *cd = NULL;
+   EINA_INLIST_FOREACH(pd->stack, cd)
+      if (cd->content == content)
+        break;
+
+   Content_Data *top_cd = NULL;
+   if (pd->stack)
+     top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
+
+   if (cd)
+     {
+        //If given content is already the top content, then do nothing.
+        if (cd == top_cd)
+          return;
+
+        //Remove the given content(existing content) to promote it to the top.
+        pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
+     }
+   else
+     {
+        cd = _content_data_new(obj, content);
+        if (!cd) return;
+
+        evas_object_smart_member_add(content, obj);
+     }
+
+   pd->stack = eina_inlist_append(pd->stack, EINA_INLIST_GET(cd));
+
+   //Loaded Event
+   Efl_Ui_Stack_Event_Loaded loaded_info;
+   loaded_info.content = content;
+   efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED, &loaded_info);
+
+   /* Apply transition to top content.
+    * Hide top content with animation. */
+   if (top_cd)
+     {
+        Eo *top_content = top_cd->content;
+
+        Efl_Canvas_Animation *orig_hide_anim =
+           efl_canvas_object_event_animation_get(top_content, 
EFL_GFX_EVENT_HIDE);
+
+        /* If content is being pushed now, then finish current animation and 
hide
+         * the content without animation. */
+        if (top_cd->on_pushing)
+          {
+             //Finish current animation.
+             efl_canvas_object_event_animation_set(top_content,
+                                                   EFL_GFX_EVENT_SHOW, NULL);
+
+             //Hide without animation.
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE, NULL);
+
+             efl_gfx_visible_set(top_content, EINA_FALSE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     orig_hide_anim);
+
+             //Deactivated Event
+             Efl_Ui_Stack_Event_Deactivated deactivated_info;
+             deactivated_info.content = top_content;
+             efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                                     &deactivated_info);
+
+             //Unloaded Event
+             Efl_Ui_Stack_Event_Unloaded unloaded_info;
+             unloaded_info.content = top_content;
+             efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                                     &unloaded_info);
+          }
+        else
+          {
+             top_cd->on_pushing = EINA_TRUE;
+
+             //Hide with animation.
+             if (!orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     hide_anim);
+
+             Transit_Data *td = calloc(1, sizeof(Transit_Data));
+             td->cd = top_cd;
+             td->orig_anim = !!(orig_hide_anim);
+             td->freeze_events = 
efl_canvas_object_freeze_events_get(top_content);
+
+             efl_event_callback_add(top_content,
+                                    EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
+                                    _anim_started_cb, NULL);
+             efl_event_callback_add(top_content,
+                                    EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
+                                    _anim_ended_cb, td);
+
+             efl_gfx_visible_set(top_content, EINA_FALSE);
+          }
+     }
+
+   /* Prepare transition for new content.
+    * Hide new content without animation. */
+     {
+        cd->on_pushing = EINA_TRUE;
+
+        Efl_Canvas_Animation *orig_hide_anim =
+           efl_canvas_object_event_animation_get(content, EFL_GFX_EVENT_HIDE);
+
+        //Hide without animation.
+        if (orig_hide_anim)
+          efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_HIDE, 
NULL);
+        efl_gfx_visible_set(content, EINA_FALSE);
+
+        //Restore original hide animation
+        if (orig_hide_anim)
+          efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_HIDE,
+                                                orig_hide_anim);
+     }
+
+   /* Apply transition to new content.
+    * Show new content with animation. */
+     {
+        evas_object_raise(content);
+
+        Efl_Canvas_Animation *orig_show_anim =
+           efl_canvas_object_event_animation_get(content, EFL_GFX_EVENT_SHOW);
+
+        //Show with animation
+        if (!orig_show_anim)
+          efl_canvas_object_event_animation_set(content, EFL_GFX_EVENT_SHOW,
+                                                show_anim);
+
+        Transit_Data *td = calloc(1, sizeof(Transit_Data));
+        td->cd = cd;
+        td->orig_anim = !!(orig_show_anim);
+        td->freeze_events = efl_canvas_object_freeze_events_get(content);
+
+        efl_event_callback_add(content, EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
+                               _anim_started_cb, NULL);
+        efl_event_callback_add(content, EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
+                               _anim_ended_cb, td);
+
+        /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
+         * internally.
+         * Therefore, efl_ui_widget_resize_object_set() is called after
+         * setting animation and efl_gfx_visible_set() is not called. */
+        efl_ui_widget_resize_object_set(obj, content);
+     }
+}
+
+static void
+_pop_content_hide_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+   Content_Data *cd = data;
+
+   cd->popped_hidden = EINA_TRUE;
+
+   _content_data_del(cd);
+}
+
+EOLIAN static Eo *
+_efl_ui_stack_pop(Eo *obj, Efl_Ui_Stack_Data *pd)
+{
+   if (!pd->stack)
+     {
+        ERR("There is no content in the stack!");
+        return NULL;
+     }
+
+   Content_Data *top_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, 
Content_Data);
+   if (!top_cd) return NULL;
+
+   pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(top_cd));
+
+   /* Apply transition to top content.
+    * Hide top content with animation. */
+     {
+        Eo *top_content = top_cd->content;
+
+        Efl_Canvas_Animation *orig_hide_anim =
+           efl_canvas_object_event_animation_get(top_content, 
EFL_GFX_EVENT_HIDE);
+
+        /* If content is being popped now, then finish current animation and 
show
+         * the content without animation. */
+        if (top_cd->on_popping)
+          {
+             //Finish current animation.
+             efl_canvas_object_event_animation_set(top_content,
+                                                   EFL_GFX_EVENT_SHOW, NULL);
+
+             //Hide without animation.
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE, NULL);
+
+             efl_gfx_visible_set(top_content, EINA_FALSE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     orig_hide_anim);
+
+             //Deactivated Event
+             Efl_Ui_Stack_Event_Deactivated deactivated_info;
+             deactivated_info.content = top_content;
+             efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                                     &deactivated_info);
+
+             //Unloaded Event
+             Efl_Ui_Stack_Event_Unloaded unloaded_info;
+             unloaded_info.content = top_content;
+             efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                                     &unloaded_info);
+
+             efl_canvas_object_event_animation_set(top_content,
+                                                   EFL_GFX_EVENT_SHOW,
+                                                   NULL);
+          }
+        else
+          {
+             top_cd->on_popping = EINA_TRUE;
+
+             //Hide with animation.
+             if (!orig_hide_anim)
+               efl_canvas_object_event_animation_set(top_content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     hide_anim);
+
+             //Deallocate content data when hide animation is finished.
+             efl_event_callback_add(top_content, EFL_GFX_EVENT_HIDE,
+                                    _pop_content_hide_cb, top_cd);
+
+             Transit_Data *td = calloc(1, sizeof(Transit_Data));
+             td->cd = top_cd;
+             td->orig_anim = !!(orig_hide_anim);
+             td->freeze_events = 
efl_canvas_object_freeze_events_get(top_content);
+
+             efl_event_callback_add(top_content,
+                                    EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
+                                    _anim_started_cb, NULL);
+             efl_event_callback_add(top_content,
+                                    EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
+                                    _anim_ended_cb, td);
+
+             efl_gfx_visible_set(top_content, EINA_FALSE);
+          }
+     }
+
+   if (pd->stack)
+     {
+        Content_Data *prev_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last,
+                                                          Content_Data);
+        if (prev_cd)
+          {
+             Eo *prev_content = prev_cd->content;
+
+             //If content is being pushed now, then finish current animation.
+             if (prev_cd->on_pushing)
+               {
+                  efl_canvas_object_event_animation_set(prev_content,
+                                                        EFL_GFX_EVENT_HIDE,
+                                                        NULL);
+               }
+             prev_cd->on_popping = EINA_TRUE;
+
+             //Loaded Event
+             Efl_Ui_Stack_Event_Loaded loaded_info;
+             loaded_info.content = prev_content;
+             efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
+                                     &loaded_info);
+
+             /* Apply transition to previous content.
+              * Show previous content with animation. */
+               {
+                  Efl_Canvas_Animation *orig_show_anim =
+                     efl_canvas_object_event_animation_get(prev_content,
+                                                           EFL_GFX_EVENT_SHOW);
+
+                  //Show with animation
+                  if (!orig_show_anim)
+                    efl_canvas_object_event_animation_set(prev_content,
+                                                          EFL_GFX_EVENT_SHOW,
+                                                          show_anim);
+
+                  Transit_Data *td = calloc(1, sizeof(Transit_Data));
+                  td->cd = prev_cd;
+                  td->orig_anim = !!(orig_show_anim);
+                  td->freeze_events =
+                     efl_canvas_object_freeze_events_get(prev_content);
+
+                  efl_event_callback_add(prev_content,
+                                         EFL_CANVAS_OBJECT_EVENT_ANIM_STARTED,
+                                         _anim_started_cb, NULL);
+                  efl_event_callback_add(prev_content,
+                                         EFL_CANVAS_OBJECT_EVENT_ANIM_ENDED,
+                                         _anim_ended_cb, td);
+
+                  /* efl_ui_widget_resize_object_set() calls 
efl_gfx_visible_set()
+                   * internally.
+                   * Therefore, efl_ui_widget_resize_object_set() is called 
after
+                   * setting animation and efl_gfx_visible_set() is not 
called. */
+                  efl_ui_widget_resize_object_set(obj, prev_content);
+               }
+
+          }
+     }
+
+   return NULL;
+}
+
+EOLIAN static void
+_efl_ui_stack_insert_before(Eo *obj, Efl_Ui_Stack_Data *pd,
+                            Eo *base_content, Eo *content)
+{
+   if (!content) return;
+
+   Content_Data *base_cd = NULL;
+   EINA_INLIST_FOREACH(pd->stack, base_cd)
+      if (base_cd->content == base_content)
+        break;
+
+   if (!base_cd)
+     {
+        ERR("The given base content is not found in the stack!");
+        return;
+     }
+
+   Content_Data *cd = _content_data_new(obj, content);
+   if (!cd) return;
+
+   pd->stack = eina_inlist_prepend_relative(pd->stack,
+                                            EINA_INLIST_GET(cd),
+                                            EINA_INLIST_GET(base_cd));
+   evas_object_smart_member_add(content, obj);
+}
+
+EOLIAN static void
+_efl_ui_stack_insert_after(Eo *obj, Efl_Ui_Stack_Data *pd,
+                           Eo *base_content, Eo *content)
+{
+   if (!content) return;
+
+   Content_Data *base_cd = NULL;
+   EINA_INLIST_FOREACH(pd->stack, base_cd)
+      if (base_cd->content == base_content)
+        break;
+
+   if (!base_cd)
+     {
+        ERR("The given base content is not found in the stack!");
+        return;
+     }
+
+   Content_Data *cd = _content_data_new(obj, content);
+   if (!cd) return;
+
+   pd->stack = eina_inlist_append_relative(pd->stack,
+                                           EINA_INLIST_GET(cd),
+                                           EINA_INLIST_GET(base_cd));
+   evas_object_smart_member_add(content, obj);
+
+   if (pd->stack->last == EINA_INLIST_GET(cd))
+     {
+        //Loaded Event
+        Efl_Ui_Stack_Event_Loaded loaded_info;
+        loaded_info.content = content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
+                                &loaded_info);
+
+        /* Do not apply transition for insert.
+         * Hide top content without animation. */
+          {
+             Efl_Canvas_Animation *orig_hide_anim =
+                efl_canvas_object_event_animation_get(base_cd->content,
+                                                      EFL_GFX_EVENT_HIDE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(base_cd->content,
+                                                     EFL_GFX_EVENT_HIDE, NULL);
+
+             efl_gfx_visible_set(base_cd->content, EINA_FALSE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(base_cd->content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     orig_hide_anim);
+          }
+
+        //Deactivated Event
+        Efl_Ui_Stack_Event_Deactivated deactivated_info;
+        deactivated_info.content = base_cd->content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                                &deactivated_info);
+
+        //Unloaded Event
+        Efl_Ui_Stack_Event_Unloaded unloaded_info;
+        unloaded_info.content = base_cd->content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                                &unloaded_info);
+
+
+        /* Do not apply transition for insert.
+         * Show new content without animation. */
+          {
+             Efl_Canvas_Animation *orig_show_anim =
+                efl_canvas_object_event_animation_get(content,
+                                                      EFL_GFX_EVENT_SHOW);
+
+             if (orig_show_anim)
+               efl_canvas_object_event_animation_set(content, 
EFL_GFX_EVENT_SHOW,
+                                                     NULL);
+
+             evas_object_raise(content);
+             /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
+              * internally.
+              * Therefore, efl_ui_widget_resize_object_set() is called after
+              * setting animation and efl_gfx_visible_set() is not called. */
+             efl_ui_widget_resize_object_set(obj, content);
+
+             if (orig_show_anim)
+               efl_canvas_object_event_animation_set(content, 
EFL_GFX_EVENT_SHOW,
+                                                     orig_show_anim);
+          }
+
+        //Activated Event
+        Efl_Ui_Stack_Event_Activated activated_info;
+        activated_info.content = content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
+                                &activated_info);
+     }
+}
+
+EOLIAN static void
+_efl_ui_stack_insert_at(Eo *obj, Efl_Ui_Stack_Data *pd,
+                        int index, Eo *content)
+{
+   if (!content)
+     {
+        ERR("The given content is NULL!");
+        return;
+     }
+
+   int count = eina_inlist_count(pd->stack);
+   if ((index < 0) || (index > count))
+     {
+        ERR("The index(%d) should be from 0 to #contents in the stack(%d)!",
+            index, count);
+        return;
+     }
+
+   Content_Data *base_cd = NULL;
+
+   if (index == count)
+     {
+        base_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
+     }
+   else
+     {
+        int i = 0;
+        EINA_INLIST_FOREACH(pd->stack, base_cd)
+          {
+             if (i == index)
+               break;
+
+             i++;
+          }
+     }
+
+   Content_Data *cd = _content_data_new(obj, content);
+   if (!cd) return;
+
+   if (index == count)
+     pd->stack = eina_inlist_append_relative(pd->stack,
+                                             EINA_INLIST_GET(cd),
+                                             EINA_INLIST_GET(base_cd));
+   else
+     pd->stack = eina_inlist_prepend_relative(pd->stack,
+                                              EINA_INLIST_GET(cd),
+                                              EINA_INLIST_GET(base_cd));
+
+   evas_object_smart_member_add(content, obj);
+
+   if (pd->stack->last == EINA_INLIST_GET(cd))
+     {
+        //Loaded Event
+        Efl_Ui_Stack_Event_Loaded loaded_info;
+        loaded_info.content = content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
+                                &loaded_info);
+
+        /* Do not apply transition for insert.
+         * Hide top content without animation. */
+          {
+             Efl_Canvas_Animation *orig_hide_anim =
+                efl_canvas_object_event_animation_get(base_cd->content,
+                                                      EFL_GFX_EVENT_HIDE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(base_cd->content,
+                                                     EFL_GFX_EVENT_HIDE, NULL);
+
+             efl_gfx_visible_set(base_cd->content, EINA_FALSE);
+
+             if (orig_hide_anim)
+               efl_canvas_object_event_animation_set(base_cd->content,
+                                                     EFL_GFX_EVENT_HIDE,
+                                                     orig_hide_anim);
+          }
+
+        //Deactivated Event
+        Efl_Ui_Stack_Event_Deactivated deactivated_info;
+        deactivated_info.content = base_cd->content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                                &deactivated_info);
+
+        //Unloaded Event
+        Efl_Ui_Stack_Event_Unloaded unloaded_info;
+        unloaded_info.content = base_cd->content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                                &unloaded_info);
+
+
+        /* Do not apply transition for insert.
+         * Show new content without animation. */
+          {
+             Efl_Canvas_Animation *orig_show_anim =
+                efl_canvas_object_event_animation_get(content,
+                                                      EFL_GFX_EVENT_SHOW);
+
+             if (orig_show_anim)
+               efl_canvas_object_event_animation_set(content, 
EFL_GFX_EVENT_SHOW,
+                                                     NULL);
+
+             evas_object_raise(content);
+             /* efl_ui_widget_resize_object_set() calls efl_gfx_visible_set()
+              * internally.
+              * Therefore, efl_ui_widget_resize_object_set() is called after
+              * setting animation and efl_gfx_visible_set() is not called. */
+             efl_ui_widget_resize_object_set(obj, content);
+
+             if (orig_show_anim)
+               efl_canvas_object_event_animation_set(content, 
EFL_GFX_EVENT_SHOW,
+                                                     orig_show_anim);
+          }
+
+        //Activated Event
+        Efl_Ui_Stack_Event_Activated activated_info;
+        activated_info.content = content;
+        efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
+                                &activated_info);
+     }
+}
+
+EOLIAN static void
+_efl_ui_stack_remove(Eo *obj, Efl_Ui_Stack_Data *pd, Eo *content)
+{
+   if (!pd->stack)
+     {
+        ERR("There is no content in the stack!");
+        return;
+     }
+
+   if (!content)
+     {
+        ERR("The given content is NULL!");
+        return;
+     }
+
+   Content_Data *cd = NULL;
+
+   EINA_INLIST_FOREACH(pd->stack, cd)
+     {
+        if (cd->content == content)
+          break;
+     }
+   if (!cd)
+     {
+        ERR("The given content does not exist in the stack!");
+        return;
+     }
+
+   Eina_Bool remove_top = EINA_FALSE;
+   if (pd->stack->last == EINA_INLIST_GET(cd))
+     remove_top = EINA_TRUE;
+
+   pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
+
+   //Deactivated Event
+   Efl_Ui_Stack_Event_Deactivated deactivated_info;
+   deactivated_info.content = cd->content;
+   efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                           &deactivated_info);
+
+   //Unloaded Event
+   Efl_Ui_Stack_Event_Unloaded unloaded_info;
+   unloaded_info.content = cd->content;
+   efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                           &unloaded_info);
+   _content_data_del(cd);
+
+   if (remove_top)
+     {
+        if (pd->stack)
+          {
+             Content_Data *new_top_cd = 
EINA_INLIST_CONTAINER_GET(pd->stack->last,
+                                                                  
Content_Data);
+             if (new_top_cd)
+               {
+                  //Loaded Event
+                  Efl_Ui_Stack_Event_Loaded loaded_info;
+                  loaded_info.content = new_top_cd->content;
+                  efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
+                                          &loaded_info);
+
+                  /* Do not apply transition for insert.
+                   * Show new content without animation. */
+                    {
+                       Efl_Canvas_Animation *orig_show_anim =
+                          
efl_canvas_object_event_animation_get(new_top_cd->content,
+                                                                
EFL_GFX_EVENT_SHOW);
+
+                       if (orig_show_anim)
+                         
efl_canvas_object_event_animation_set(new_top_cd->content,
+                                                               
EFL_GFX_EVENT_SHOW,
+                                                               NULL);
+
+                       evas_object_raise(new_top_cd->content);
+                       /* efl_ui_widget_resize_object_set() calls 
efl_gfx_visible_set()
+                        * internally.
+                        * Therefore, efl_ui_widget_resize_object_set() is 
called after
+                        * setting animation and efl_gfx_visible_set() is not 
called. */
+                       efl_ui_widget_resize_object_set(obj, 
new_top_cd->content);
+
+                       if (orig_show_anim)
+                         
efl_canvas_object_event_animation_set(new_top_cd->content,
+                                                               
EFL_GFX_EVENT_SHOW,
+                                                               orig_show_anim);
+                    }
+
+                  //Activated Event
+                  Efl_Ui_Stack_Event_Activated activated_info;
+                  activated_info.content = new_top_cd->content;
+                  efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
+                                          &activated_info);
+               }
+          }
+     }
+}
+
+EOLIAN static void
+_efl_ui_stack_remove_at(Eo *obj, Efl_Ui_Stack_Data *pd,
+                        int index)
+{
+   if (!pd->stack)
+     {
+        ERR("There is no content in the stack!");
+        return;
+     }
+
+   int count = eina_inlist_count(pd->stack);
+   if ((index < 0) || (index >= count))
+     {
+        ERR("The index(%d) should be from 0 to (#contents - 1) in the 
stack(%d)!",
+            index, count);
+        return;
+     }
+
+   Content_Data *cd = NULL;
+   int i = 0;
+   EINA_INLIST_FOREACH(pd->stack, cd)
+     {
+        if (i == index)
+          break;
+        i++;
+     }
+
+   Eina_Bool remove_top = EINA_FALSE;
+   if (pd->stack->last == EINA_INLIST_GET(cd))
+     remove_top = EINA_TRUE;
+
+   pd->stack = eina_inlist_remove(pd->stack, EINA_INLIST_GET(cd));
+
+   //Deactivated Event
+   Efl_Ui_Stack_Event_Deactivated deactivated_info;
+   deactivated_info.content = cd->content;
+   efl_event_callback_call(obj, EFL_UI_STACK_EVENT_DEACTIVATED,
+                           &deactivated_info);
+
+   //Unloaded Event
+   Efl_Ui_Stack_Event_Unloaded unloaded_info;
+   unloaded_info.content = cd->content;
+   efl_event_callback_call(obj, EFL_UI_STACK_EVENT_UNLOADED,
+                           &unloaded_info);
+   _content_data_del(cd);
+
+   //FIXME: Apply transition here.
+   if (remove_top)
+     {
+        if (pd->stack)
+          {
+             Content_Data *new_top_cd = 
EINA_INLIST_CONTAINER_GET(pd->stack->last,
+                                                                  
Content_Data);
+             if (new_top_cd)
+               {
+                  //Loaded Event
+                  Efl_Ui_Stack_Event_Loaded loaded_info;
+                  loaded_info.content = new_top_cd->content;
+                  efl_event_callback_call(obj, EFL_UI_STACK_EVENT_LOADED,
+                                          &loaded_info);
+
+                  /* Do not apply transition for insert.
+                   * Show new content without animation. */
+                    {
+                       Efl_Canvas_Animation *orig_show_anim =
+                          
efl_canvas_object_event_animation_get(new_top_cd->content,
+                                                                
EFL_GFX_EVENT_SHOW);
+
+                       if (orig_show_anim)
+                         
efl_canvas_object_event_animation_set(new_top_cd->content,
+                                                               
EFL_GFX_EVENT_SHOW,
+                                                               NULL);
+
+                       evas_object_raise(new_top_cd->content);
+                       /* efl_ui_widget_resize_object_set() calls 
efl_gfx_visible_set()
+                        * internally.
+                        * Therefore, efl_ui_widget_resize_object_set() is 
called after
+                        * setting animation and efl_gfx_visible_set() is not 
called. */
+                       efl_ui_widget_resize_object_set(obj, 
new_top_cd->content);
+
+                       if (orig_show_anim)
+                         
efl_canvas_object_event_animation_set(new_top_cd->content,
+                                                               
EFL_GFX_EVENT_SHOW,
+                                                               orig_show_anim);
+                    }
+
+                  //Activated Event
+                  Efl_Ui_Stack_Event_Activated activated_info;
+                  activated_info.content = new_top_cd->content;
+                  efl_event_callback_call(obj, EFL_UI_STACK_EVENT_ACTIVATED,
+                                          &activated_info);
+               }
+          }
+     }
+}
+
+EOLIAN static int
+_efl_ui_stack_index_get(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd, 
Efl_Canvas_Object *content)
+{
+   if (!pd->stack)
+     {
+        ERR("There is no content in the stack!");
+        return -1;
+     }
+
+   if (!content)
+     {
+        ERR("The given content is NULL!");
+        return -1;
+     }
+
+   Content_Data *cd = NULL;
+   int index = 0;
+   int count = eina_inlist_count(pd->stack);
+
+   EINA_INLIST_FOREACH(pd->stack, cd)
+     {
+        if (cd->content == content)
+          break;
+        index++;
+     }
+
+   //The given content is not found.
+   if (index == count) return -1;
+
+   return index;
+}
+
+EOLIAN static Eo *
+_efl_ui_stack_content_get(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd, int 
index)
+{
+   if (!pd->stack)
+     {
+        ERR("There is no content in the stack!");
+        return NULL;
+     }
+
+   int count = eina_inlist_count(pd->stack);
+   if ((index < 0) || (index >= count))
+     {
+        ERR("The index(%d) should be from 0 to (#contents - 1) in the 
stack(%d)!",
+            index, count);
+        return NULL;
+     }
+
+   Content_Data *cd = NULL;
+   int i = 0;
+   EINA_INLIST_FOREACH(pd->stack, cd)
+     {
+        if (i == index)
+          break;
+        i++;
+     }
+
+   if (cd)
+     return cd->content;
+
+   return NULL;
+}
+
+EOLIAN static Eo *
+_efl_ui_stack_top(Eo *obj EINA_UNUSED, Efl_Ui_Stack_Data *pd)
+{
+   if (!pd->stack) return NULL;
+
+   Content_Data *cd = EINA_INLIST_CONTAINER_GET(pd->stack->last, Content_Data);
+   if (!cd) return NULL;
+
+   return cd->content;
+}
+
+EOLIAN static Eo *
+_efl_ui_stack_efl_object_constructor(Eo *obj, Efl_Ui_Stack_Data *pd 
EINA_UNUSED)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   efl_canvas_object_type_set(obj, MY_CLASS_NAME);
+
+   //Default Show Animation
+   show_anim = efl_add(EFL_CANVAS_ANIMATION_ALPHA_CLASS, obj);
+   efl_animation_alpha_set(show_anim, 0.0, 1.0);
+   efl_animation_duration_set(show_anim, 0.5);
+   efl_animation_final_state_keep_set(show_anim, EINA_TRUE);
+
+   //Default Hide Animation
+   hide_anim = efl_add(EFL_CANVAS_ANIMATION_ALPHA_CLASS, obj);
+   efl_animation_alpha_set(hide_anim, 1.0, 0.0);
+   efl_animation_duration_set(hide_anim, 0.5);
+   efl_animation_final_state_keep_set(hide_anim, EINA_TRUE);
+
+   return obj;
+}
+
+#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 @@
+struct Efl.Ui.Stack.Event_Loaded {
+   [[Information of loaded event.]]
+   content: Efl.Canvas.Object; [[Loaded content.]]
+}
+
+struct Efl.Ui.Stack.Event_Unloaded {
+   [[Information of unloaded event.]]
+   content: Efl.Canvas.Object; [[Unloaded content.]]
+}
+
+struct Efl.Ui.Stack.Event_Activated {
+   [[Information of activated event.]]
+   content: Efl.Canvas.Object; [[Activated content.]]
+}
+
+struct Efl.Ui.Stack.Event_Deactivated {
+   [[Information of deactivated event.]]
+   content: Efl.Canvas.Object; [[Deactivated content.]]
+}
+
+class Efl.Ui.Stack (Efl.Ui.Layout)
+{
+   [[Stack widget.
+          
+     Stack widget arranges objects in stack structure by pushing and poping 
them.
+   ]]
+   methods {
+      push {
+         [[Pushes a new object to the top of the stack and shows it.
+         ]]
+         params {
+            @in content: Efl.Canvas.Object;
+               [[The pushed object which becomes the top content of the 
stack.]]
+         }
+      }
+      pop {
+         [[Pops the top content from the stack and deletes it.
+         ]]
+         return: Efl.Canvas.Object;
+            [[The top content which is removed from the stack.]]
+      }
+      insert_before {
+         [[Inserts an object before the given base content in the stack.
+         ]]
+         params {
+            @in base_content: Efl.Canvas.Object;
+               [[$content is inserted before this $base_content.]]
+            @in content: Efl.Canvas.Object;
+               [[The inserted object in the stack.]]
+         }
+      }
+      insert_after {
+         [[Inserts an object after the given base content in the stack.
+         ]]
+         params {
+            @in base_content: Efl.Canvas.Object;
+               [[$content is inserted after this $base_content.]]
+            @in content: Efl.Canvas.Object;
+               [[The inserted object in the stack.]]
+         }
+      }
+      insert_at {
+         [[Inserts an object at the given place in the stack.
+         ]]
+         params {
+            @in index: int;
+               [[The index of the inserted object in the stack.
+                 $index begins from bottom to top of the stack.
+                 $index of the bottom content is 0.
+               ]]
+            @in content: Efl.Canvas.Object;
+               [[The inserted object in the stack.]]
+         }
+      }
+      remove {
+         [[Removes the given content in the stack.
+         ]]
+         params {
+            @in content: Efl.Canvas.Object;
+               [[The removed content from the stack.]]
+         }
+      }
+      remove_at {
+         [[Removes a content matched to the given index in the stack.
+         ]]
+         params {
+            @in index: int;
+               [[The index of the removed object in the stack.
+                 $index begins from bottom to top of the stack.
+                 $index of the bottom content is 0.
+               ]]
+         }
+      }
+      index_get {
+         [[Gets the index of the given content in the stack.
+           The index begins from bottom to top of the stack.
+           The index of the bottom content is 0.
+         ]]
+         return: int;
+            [[The index of $content in the stack.]]
+         params {
+            @in content: Efl.Canvas.Object;
+               [[The content matched to the index to be returned in the 
stack.]]
+         }
+      }
+      content_get {
+         [[Gets the content matched to the given index in the stack.
+         ]]
+         return: Efl.Canvas.Object;
+            [[The content matched to $index in the stack.]]
+         params {
+            @in index: int;
+               [[The index of the content to be returned in the stack.]]
+         }
+      }
+      top {
+         [[Gets the top content in the stack.
+         ]]
+         return: Efl.Canvas.Object; [[The top content in the stack.]]
+      }
+   }
+   implements {
+      Efl.Object.constructor;
+   }
+   events {
+      loaded;      [[Called when content is loaded right before transition.]]
+      unloaded;    [[Called when content is unloaded right after being 
deactivated.]]
+      activated;   [[Called when content is activated right after transition.]]
+      deactivated; [[Called when content is deactivated right after 
transition.]]
+   }
+}
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 @@
+#ifndef EFL_UI_WIDGET_STACK_H
+#define EFL_UI_WIDGET_STACK_H
+
+typedef struct _Efl_Ui_Stack_Data Efl_Ui_Stack_Data;
+struct _Efl_Ui_Stack_Data
+{
+   Eina_Inlist *stack; /* the last item is the top item */
+};
+
+typedef struct _Content_Data Content_Data;
+struct _Content_Data
+{
+   EINA_INLIST;
+
+   Eo        *stack;
+   Eo        *content;
+   Eina_Bool  on_pushing : 1;
+   Eina_Bool  on_popping : 1;
+   Eina_Bool  popped_hidden : 1;
+};
+
+typedef struct _Transit_Data Transit_Data;
+struct _Transit_Data
+{
+   Content_Data *cd;
+   Eina_Bool     orig_anim;
+   Eina_Bool     freeze_events;
+};
+
+#endif

-- 


Reply via email to