aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib/elementary/efl_ui_stack.c
blob: 921c4ac33605910f722b187a748eb333af10c3a3 (plain) (tree)















































































                                                                              
                                                               



                                                              
                                                                         






                                                          
                                                           






































































                                                                                    
              
      




























































                                                                                         







                                              
                                                                                     


                                 

                                                                                          


                                         
                                                                                   








                                                                
                                                                                     


                             
                                                                                   











                                                                             
                                                                               

                                                                       
                                                                               























                                                                                   








                                                                      
                                                                                         






                                                                                 
                                                                                    



                                                                 
                                                                                      
 
                                                                 


                                                                 
                                                                               














                                                                         
                                                                             








                                                                 
                                                                               


                                                                       
                                                                           













                                                                                  
                                                                 






                                                                          
                                            
 







                                                                             
 




                                                               
 





                                                                                 
 




                                                                               
 




                                                                  
 





                                                                         
 




                                                                                    





































































                                                                       
                                                                                 


                                                                      
                                                                                      
 
                                                                      


                                                                      
                                                                               




















                                                                     
                                                                                 

                                
                                                                                        


                                                           
                                                                                    

                                                                            
                                                                                    


                                                           
                                                                                        









































































                                                                            
                                                                                 


                                                                      
                                                                                      
 
                                                                      


                                                                      
                                                                               




















                                                                     
                                                                                 

                                
                                                                                        


                                                           
                                                                                    

                                                                            
                                                                                    


                                                           
                                                                                        































































                                                                                  







                                                                    
                



















                                                                                         
                





                                                                       
























































                                                                                  







                                                                    
                



















                                                                                         
                





                                                                       









































































                                                                                               

























                                                                                
#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 *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_desc, 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_desc == EFL_GFX_ENTITY_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_ENTITY_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_ENTITY_EVENT_SHOW, NULL);

             //Hide without animation.
             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(top_content,
                                                     EFL_GFX_ENTITY_EVENT_HIDE, NULL);

             efl_gfx_entity_visible_set(top_content, EINA_FALSE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(top_content,
                                                     EFL_GFX_ENTITY_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_ENTITY_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_entity_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_ENTITY_EVENT_HIDE);

        //Hide without animation.
        if (orig_hide_anim)
          efl_canvas_object_event_animation_set(content, EFL_GFX_ENTITY_EVENT_HIDE, NULL);
        efl_gfx_entity_visible_set(content, EINA_FALSE);

        //Restore original hide animation
        if (orig_hide_anim)
          efl_canvas_object_event_animation_set(content, EFL_GFX_ENTITY_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_ENTITY_EVENT_SHOW);

        //Show with animation
        if (!orig_show_anim)
          efl_canvas_object_event_animation_set(content, EFL_GFX_ENTITY_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_entity_visible_set()
         * internally.
         * Therefore, efl_ui_widget_resize_object_set() is called after
         * setting animation and efl_gfx_entity_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);

   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_ENTITY_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_ENTITY_EVENT_SHOW, NULL);

             //Hide without animation.
             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(top_content,
                                                     EFL_GFX_ENTITY_EVENT_HIDE, NULL);

             efl_gfx_entity_visible_set(top_content, EINA_FALSE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(top_content,
                                                     EFL_GFX_ENTITY_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_ENTITY_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_ENTITY_EVENT_HIDE,
                                                     hide_anim);

             //Deallocate content data when hide animation is finished.
             efl_event_callback_add(top_content, EFL_GFX_ENTITY_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_entity_visible_set(top_content, EINA_FALSE);
          }
     }

   if (pd->stack)
     {
        Content_Data *prev_cd = EINA_INLIST_CONTAINER_GET(pd->stack->last,
                                                          Content_Data);
        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_ENTITY_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_ENTITY_EVENT_SHOW);

             //Show with animation
             if (!orig_show_anim)
               efl_canvas_object_event_animation_set(prev_content,
                                                     EFL_GFX_ENTITY_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_entity_visible_set()
              * internally.
              * Therefore, efl_ui_widget_resize_object_set() is called after
              * setting animation and efl_gfx_entity_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_ENTITY_EVENT_HIDE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(base_cd->content,
                                                     EFL_GFX_ENTITY_EVENT_HIDE, NULL);

             efl_gfx_entity_visible_set(base_cd->content, EINA_FALSE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(base_cd->content,
                                                     EFL_GFX_ENTITY_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_ENTITY_EVENT_SHOW);

             if (orig_show_anim)
               efl_canvas_object_event_animation_set(content, EFL_GFX_ENTITY_EVENT_SHOW,
                                                     NULL);

             evas_object_raise(content);
             /* efl_ui_widget_resize_object_set() calls efl_gfx_entity_visible_set()
              * internally.
              * Therefore, efl_ui_widget_resize_object_set() is called after
              * setting animation and efl_gfx_entity_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_ENTITY_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_ENTITY_EVENT_HIDE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(base_cd->content,
                                                     EFL_GFX_ENTITY_EVENT_HIDE, NULL);

             efl_gfx_entity_visible_set(base_cd->content, EINA_FALSE);

             if (orig_hide_anim)
               efl_canvas_object_event_animation_set(base_cd->content,
                                                     EFL_GFX_ENTITY_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_ENTITY_EVENT_SHOW);

             if (orig_show_anim)
               efl_canvas_object_event_animation_set(content, EFL_GFX_ENTITY_EVENT_SHOW,
                                                     NULL);

             evas_object_raise(content);
             /* efl_ui_widget_resize_object_set() calls efl_gfx_entity_visible_set()
              * internally.
              * Therefore, efl_ui_widget_resize_object_set() is called after
              * setting animation and efl_gfx_entity_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_ENTITY_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);
             //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_ENTITY_EVENT_SHOW);

                  if (orig_show_anim)
                    efl_canvas_object_event_animation_set(new_top_cd->content,
                                                          EFL_GFX_ENTITY_EVENT_SHOW,
                                                          NULL);

                  evas_object_raise(new_top_cd->content);
                  /* efl_ui_widget_resize_object_set() calls efl_gfx_entity_visible_set()
                   * internally.
                   * Therefore, efl_ui_widget_resize_object_set() is called after
                   * setting animation and efl_gfx_entity_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_ENTITY_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);
             //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_ENTITY_EVENT_SHOW);

                  if (orig_show_anim)
                    efl_canvas_object_event_animation_set(new_top_cd->content,
                                                          EFL_GFX_ENTITY_EVENT_SHOW,
                                                          NULL);

                  evas_object_raise(new_top_cd->content);
                  /* efl_ui_widget_resize_object_set() calls efl_gfx_entity_visible_set()
                   * internally.
                   * Therefore, efl_ui_widget_resize_object_set() is called after
                   * setting animation and efl_gfx_entity_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_ENTITY_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);

   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"