I am sending two patches to add a transition layout to elm_box. The
transition layout is used to display an animation when switching layouts in
elm_box. A sample video of this layout working can be found in
http://www.youtube.com/watch?v=kjFCyRFoT7A .
The first patch is for evas_object_box. Some changes in this file were
necessary, because it was important for the layout function to know if any
child has been added or removed during the animation. The other patch is for
elm_box, adding the layout.

Thanks,
Otávio Pontes
commit d050f92e55e879154d452fa513f6230ec0e4d8af
Author: Otavio Pontes <ota...@profusion.mobi>
Date:   Thu Sep 16 14:10:05 2010 -0300

    Adding callback for box to be called when a child is added or removed.
    
    Also sets the children_changed flag when changing children list.

diff --git a/evas/src/lib/Evas.h b/evas/src/lib/Evas.h
index 052cae5..42a3764 100644
--- a/evas/src/lib/Evas.h
+++ b/evas/src/lib/Evas.h
@@ -1987,6 +1987,7 @@ struct _Evas_Smart_Cb_Description
 	 void (*free_data)(void *data);
       } layout;
       Eina_Bool layouting : 1;
+      Eina_Bool children_changed : 1;
    };
 
    struct _Evas_Object_Box_Option
diff --git a/evas/src/lib/canvas/evas_object_box.c b/evas/src/lib/canvas/evas_object_box.c
index 4a5e667..b5b6548 100644
--- a/evas/src/lib/canvas/evas_object_box.c
+++ b/evas/src/lib/canvas/evas_object_box.c
@@ -25,6 +25,13 @@ struct _Evas_Object_Box_Accessor
  */
 
 static const char _evas_object_box_type[] = "Evas_Object_Box";
+static const char SIG_CHILD_ADDED[] = "child,added";
+static const char SIG_CHILD_REMOVED[] = "child,removed";
+static const Evas_Smart_Cb_Description _signals[] = {
+   {SIG_CHILD_ADDED, ""},
+   {SIG_CHILD_REMOVED, ""},
+   {NULL, NULL}
+};
 
 
 static void _sizing_eval(Evas_Object *obj);
@@ -237,6 +244,8 @@ _evas_object_box_append_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas
      return NULL;
 
    priv->children = eina_list_append(priv->children, opt);
+   priv->children_changed = EINA_TRUE;
+   evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt);
 
    return opt;
 }
@@ -251,6 +260,8 @@ _evas_object_box_prepend_default(Evas_Object *o, Evas_Object_Box_Data *priv, Eva
      return NULL;
 
    priv->children = eina_list_prepend(priv->children, opt);
+   priv->children_changed = EINA_TRUE;
+   evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt);
 
    return opt;
 }
@@ -273,6 +284,8 @@ _evas_object_box_insert_before_default(Evas_Object *o, Evas_Object_Box_Data *pri
 
 	     priv->children = eina_list_prepend_relative
 	       (priv->children, new_opt, opt);
+             priv->children_changed = EINA_TRUE;
+             evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
 	     return new_opt;
 	  }
      }
@@ -298,6 +311,8 @@ _evas_object_box_insert_after_default(Evas_Object *o, Evas_Object_Box_Data *priv
 
 	     priv->children = eina_list_append_relative
 		(priv->children, new_opt, opt);
+             priv->children_changed = EINA_TRUE;
+             evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
 	     return new_opt;
 	  }
      }
@@ -320,6 +335,8 @@ _evas_object_box_insert_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, E
 	  return NULL;
 
         priv->children = eina_list_prepend(priv->children, new_opt);
+        priv->children_changed = EINA_TRUE;
+        evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
         return new_opt;
      }
 
@@ -337,6 +354,8 @@ _evas_object_box_insert_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, E
 
 	     priv->children = eina_list_prepend_relative
 	       (priv->children, new_opt, opt);
+             priv->children_changed = EINA_TRUE;
+             evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
 	     return new_opt;
 	  }
      }
@@ -368,6 +387,8 @@ _evas_object_box_remove_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas
 	  {
 	     priv->children = eina_list_remove(priv->children, opt);
 	     api->option_free(o, priv, opt);
+             priv->children_changed = EINA_TRUE;
+             evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj);
 
 	     return obj;
 	  }
@@ -405,6 +426,8 @@ _evas_object_box_remove_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, u
 
    priv->children = eina_list_remove_list(priv->children, node);
    api->option_free(o, priv, opt);
+   priv->children_changed = EINA_TRUE;
+   evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj);
    return obj;
 }
 
@@ -497,6 +520,7 @@ _evas_object_box_smart_calculate(Evas_Object *o)
            priv->layouting = 1;
            priv->layout.cb(o, priv, priv->layout.data);
            priv->layouting = 0;
+           priv->children_changed = EINA_FALSE;
        }
    else
      ERR("No layout function set for %p box.", o);
@@ -509,6 +533,7 @@ _evas_object_box_smart_set_user(Evas_Object_Box_Api *api)
    api->base.del = _evas_object_box_smart_del;
    api->base.resize = _evas_object_box_smart_resize;
    api->base.calculate = _evas_object_box_smart_calculate;
+   api->base.callbacks = _signals;
 
    api->append = _evas_object_box_append_default;
    api->prepend = _evas_object_box_prepend_default;
commit 4f61bb209039e9d273dcbf38fc75a484ad218242
Author: Otavio Pontes <ota...@profusion.mobi>
Date:   Thu Sep 16 15:50:56 2010 -0300

    Creating a transition layout for elm_box.
    
    This layout is used to perform an animation when changing layouts in box

diff --git a/TMP/st/elementary/src/lib/Elementary.h.in b/TMP/st/elementary/src/lib/Elementary.h.in
index fef93d3..357c275 100644
--- a/TMP/st/elementary/src/lib/Elementary.h.in
+++ b/TMP/st/elementary/src/lib/Elementary.h.in
@@ -467,6 +467,29 @@ extern "C" {
     * "clicked" - the user clicked the image
     */
 
+   typedef struct _Elm_Box_Transition Elm_Box_Transition;
+   struct _Elm_Box_Transition
+   {
+      double initial_time;
+      double duration;
+      Eina_Bool animation_ended:1;
+      Eina_Bool recalculate:1;
+      Ecore_Animator *animator;
+
+      struct
+      {
+         Evas_Object_Box_Layout layout;
+         void *data;
+         void(*free_data)(void *data);
+      } start, end;
+
+      void(*transition_end_cb)(void *data);
+      void *transition_end_data;
+      void (*transition_end_free_data)(void *data);
+      Eina_List *objs;
+      Evas_Object *box;
+   };
+
    EAPI Evas_Object *elm_box_add(Evas_Object *parent);
    EAPI void         elm_box_horizontal_set(Evas_Object *obj, Eina_Bool horizontal);
    EAPI void         elm_box_homogenous_set(Evas_Object *obj, Eina_Bool homogenous);
@@ -477,6 +500,10 @@ extern "C" {
    EAPI void         elm_box_clear(Evas_Object *obj);
    EAPI void         elm_box_unpack(Evas_Object *obj, Evas_Object *subobj);
    EAPI void         elm_box_unpack_all(Evas_Object *obj);
+   EAPI void         elm_box_layout_set(Evas_Object *obj, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data));
+   EAPI void         elm_box_layout_transition(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data);
+   EAPI Elm_Box_Transition *elm_box_transition_new(const double duration, Evas_Object_Box_Layout start_layout, void *start_layout_data, void(*start_layout_free_data)(void *data), Evas_Object_Box_Layout end_layout, void *end_layout_data, void(*end_layout_free_data)(void *data), void(*transition_end_cb)(void *data), void *transition_end_data);
+   EAPI void         elm_box_transition_free(void *data);
    /* smart callbacks called:
     */
 
diff --git a/TMP/st/elementary/src/lib/elm_box.c b/TMP/st/elementary/src/lib/elm_box.c
index cf3f29d..d9356cb 100644
--- a/TMP/st/elementary/src/lib/elm_box.c
+++ b/TMP/st/elementary/src/lib/elm_box.c
@@ -1,6 +1,8 @@
 #include <Elementary.h>
 #include "elm_priv.h"
 
+#define SIG_CHILD_ADDED "child,added"
+#define SIG_CHILD_REMOVED "child,removed"
 /**
  * @defgroup Box Box
  *
@@ -19,6 +21,7 @@
  * NOTE: Objects should not be added to box objects using _add() calls.
  */
 typedef struct _Widget_Data Widget_Data;
+typedef struct _Transition_Animation_Data Transition_Animation_Data;
 
 struct _Widget_Data
 {
@@ -27,6 +30,15 @@ struct _Widget_Data
    Eina_Bool homogeneous:1;
 };
 
+struct _Transition_Animation_Data
+{
+   Evas_Object *obj;
+   struct
+   {
+      int x, y, w, h;
+   } start, end;
+};
+
 static const char *widtype = NULL;
 static void _del_hook(Evas_Object *obj);
 static void _sizing_eval(Evas_Object *obj);
@@ -90,6 +102,169 @@ _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
    _els_box_layout(o, priv, wd->horizontal, wd->homogeneous);
 }
 
+static Eina_Bool
+_transition_animation(void *data)
+{
+   evas_object_smart_changed(data);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_transition_layout_child_added(void *data, Evas_Object *obj, void *event_info)
+{
+   Transition_Animation_Data *tad;
+   Evas_Object_Box_Option *opt = event_info;
+   Elm_Box_Transition *layout_data = data;
+   tad = calloc(1, sizeof(Transition_Animation_Data));
+   if (!tad)
+      return;
+   tad->obj = opt->obj;
+   layout_data->objs = eina_list_append(layout_data->objs, tad);
+   layout_data->recalculate = EINA_TRUE;
+}
+
+static void
+_transition_layout_child_removed(void *data, Evas_Object *obj, void *event_info)
+{
+   Eina_List *l;
+   Transition_Animation_Data *tad;
+   Elm_Box_Transition *layout_data = data;
+
+   EINA_LIST_FOREACH(layout_data->objs, l, tad)
+     {
+        if (tad->obj == event_info)
+          {
+             free(eina_list_data_get(l));
+             layout_data->objs = eina_list_remove_list(layout_data->objs, l);
+             layout_data->recalculate = EINA_TRUE;
+             break;
+          }
+     }
+}
+
+static void
+_transition_layout_obj_resize_cb (void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Elm_Box_Transition *layout_data = data;
+   layout_data->recalculate = EINA_TRUE;
+}
+
+static void
+_transition_layout_calculate_coords(Evas_Object *obj, Evas_Object_Box_Data *priv,
+      Elm_Box_Transition *layout_data)
+{
+   Eina_List *l;
+   Transition_Animation_Data *tad;
+   Evas_Coord x, y, w, h;
+
+   const double curtime = ecore_loop_time_get();
+   layout_data->duration = layout_data->duration - (curtime - layout_data->initial_time);
+   layout_data->initial_time = curtime;
+
+   evas_object_geometry_get(obj, &x, &y, &w, &h);
+   EINA_LIST_FOREACH(layout_data->objs, l, tad)
+     {
+        evas_object_geometry_get(tad->obj, &tad->start.x, &tad->start.y,
+              &tad->start.w, &tad->start.h);
+        tad->start.x = tad->start.x - x;
+        tad->start.y = tad->start.y - y;
+     }
+   layout_data->end.layout(obj, priv, layout_data->end.data);
+   EINA_LIST_FOREACH(layout_data->objs, l, tad)
+     {
+        evas_object_geometry_get(tad->obj, &tad->end.x, &tad->end.y,
+              &tad->end.w, &tad->end.h);
+        tad->end.x = tad->end.x - x;
+        tad->end.y = tad->end.y - y;
+     }
+}
+
+static Eina_Bool
+_transition_layout_load_children_list(Evas_Object_Box_Data *priv,
+      Elm_Box_Transition *layout_data)
+{
+   Eina_List *l;
+   Evas_Object_Box_Option *opt;
+   Transition_Animation_Data *tad;
+
+   EINA_LIST_FREE(layout_data->objs, tad)
+      free(tad);
+
+   EINA_LIST_FOREACH(priv->children, l, opt)
+     {
+        tad = calloc(1, sizeof(Transition_Animation_Data));
+        if (!tad)
+          {
+             EINA_LIST_FREE(layout_data->objs, tad)
+                free(tad);
+             layout_data->objs = NULL;
+             return EINA_FALSE;
+          }
+        tad->obj = opt->obj;
+        layout_data->objs = eina_list_append(layout_data->objs, tad);
+
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_transition_layout_animation_start(Evas_Object *obj, Evas_Object_Box_Data *priv,
+      Elm_Box_Transition *layout_data, Eina_Bool(*transition_animation_cb)(void *data))
+{
+   layout_data->start.layout(obj, priv, layout_data->start.data);
+   layout_data->box = obj;
+   layout_data->initial_time = ecore_loop_time_get();
+
+   if (!_transition_layout_load_children_list(priv, layout_data))
+      return EINA_FALSE;
+   _transition_layout_calculate_coords(obj, priv, layout_data);
+
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _transition_layout_obj_resize_cb, layout_data);
+   evas_object_smart_callback_add(obj, SIG_CHILD_ADDED, _transition_layout_child_added, layout_data);
+   evas_object_smart_callback_add(obj, SIG_CHILD_REMOVED, _transition_layout_child_removed, layout_data);
+   if (!layout_data->animator)
+      layout_data->animator = ecore_animator_add(transition_animation_cb, obj);
+   layout_data->animation_ended = EINA_FALSE;
+   return EINA_TRUE;
+}
+
+static void
+_transition_layout_animation_stop(Elm_Box_Transition *layout_data)
+{
+   layout_data->animation_ended = EINA_TRUE;
+   if (layout_data->animator)
+     {
+        ecore_animator_del(layout_data->animator);
+        layout_data->animator = NULL;
+     }
+
+   if (layout_data->transition_end_cb)
+      layout_data->transition_end_cb(layout_data->transition_end_data);
+}
+
+static void
+_transition_layout_animation_exec(Evas_Object *obj, Evas_Object_Box_Data *priv,
+      Elm_Box_Transition *layout_data, const double curtime)
+{
+   Eina_List *l;
+   Transition_Animation_Data *tad;
+   Evas_Coord x, y, w, h;
+   Evas_Coord cur_x, cur_y, cur_w, cur_h;
+   evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+
+   double progress = (curtime - layout_data->initial_time) / layout_data->duration;
+
+   EINA_LIST_FOREACH(layout_data->objs, l, tad)
+     {
+        cur_x = x + tad->start.x + ((tad->end.x - tad->start.x) * progress);
+        cur_y = y + tad->start.y + ((tad->end.y - tad->start.y) * progress);
+        cur_w = tad->start.w + ((tad->end.w - tad->start.w) * progress);
+        cur_h = tad->start.h + ((tad->end.h - tad->start.h) * progress);
+        evas_object_move(tad->obj, cur_x, cur_y);
+        evas_object_resize(tad->obj, cur_w, cur_h);
+     }
+}
 
 /**
  * Add a new box to the parent
@@ -354,3 +529,173 @@ elm_box_unpack_all(Evas_Object *obj)
    if (!wd) return;
    evas_object_box_remove_all(wd->box, 0);
 }
+
+/**
+ * Set the callback layout function (@p cb) to the @p obj elm_box class.
+ *
+ * This function will use evas_object_box_layout_set() to set @p cb as the
+ * layout callback function for this box object.
+ * All layout funtions from evas_object_box can be used as @p cb. Some examples
+ * are evas_object_box_layout_horizontal, evas_object_box_layout_vertical and
+ * evas_object_box_layout_stack. elm_box_layout_transition can also be used.
+ * If @p cb is NULL, the default layout function from elm_box will be used.
+ *
+ * @note Changing the layout function will make horizontal/homogeneous fields
+ * from Widget_Data have NO further usage as they are controlled by default
+ * layout function. So calling elm_box_horizontal_set() or
+ * elm_box_homogenous_set() won't affect layout behavior.
+ *
+ * @param obj The box object
+ * @param cb The callback function used for layout
+ * @param data Data that will be passed to layout function
+ * @param free_data Function called to free @p data
+ *
+ * @ingroup Box
+ */
+EAPI void
+elm_box_layout_set(Evas_Object *obj, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data))
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   if (cb)
+     evas_object_box_layout_set(wd->box, cb, data, free_data);
+   else
+     evas_object_box_layout_set(wd->box, _layout, wd, NULL);
+}
+
+/**
+ * Layout function which display a transition animation from start layout to end layout.
+ *
+ * This function should no be called directly. It may be used by elm_box_layout_set() or
+ * as_object_box_layout_set() as a layout function.
+ * The @p data passed to this function must be a Elm_Box_Transition*, that can be created
+ * using elm_box_transition_new() and freed with elm_box_transition_free().
+ *
+ * Usage Example:
+ * @code
+ * Evas_Object *box = elm_box_add(parent);
+ * Elm_Box_Transition *t = elm_box_transition_new(...add params here...);
+ * elm_box_layout_set(box, elm_box_layout_transition, t, elm_box_transition_free);
+ * @endcode
+ *
+ * @see elm_box_transition_new
+ * @see elm_box_transition_free
+ *
+ * @ingroup Box
+ */
+EAPI void
+elm_box_layout_transition(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data)
+{
+   Elm_Box_Transition *box_data = data;
+   const double curtime = ecore_loop_time_get();
+
+   if (box_data->animation_ended)
+     {
+          box_data->end.layout(obj, priv, box_data->end.data);
+          return;
+     }
+
+   if (!box_data->animator)
+     {
+        if (!_transition_layout_animation_start(obj, priv, box_data,
+            _transition_animation))
+           return;
+     }
+   else
+     {
+        if (box_data->recalculate)
+          {
+             _transition_layout_calculate_coords(obj, priv, box_data);
+             box_data->recalculate = EINA_FALSE;
+          }
+     }
+
+   if ((curtime >= box_data->duration + box_data->initial_time))
+      _transition_layout_animation_stop(box_data);
+   else
+      _transition_layout_animation_exec(obj, priv, box_data, curtime);
+}
+
+/**
+ * Create a new Elm_Box_Transition setted with informed parameters.
+ *
+ * The returned instance may be used as data parameter to elm_box_layout_transition()
+ * and should be freed with elm_box_transition_free().
+ *
+ * @param start_layout The layout function that will be used to start the animation
+ * @param start_layout_data The data to be passed the @p start_layout function
+ * @param start_layout_free_data Function to free @p start_layout_data
+ * @param end_layout The layout function that will be used to end the animation
+ * @param end_layout_free_data The data to be passed the @p end_layout function
+ * @param end_layout_free_data Function to free @p end_layout_data
+ * @param transition_end_cb Callback function called when animation ends
+ * @param transition_end_data Data to be passed to @p transition_end_cb
+ * @return An instance of Elm_Box_Transition setted with informed parameters
+ *
+ * @see elm_box_transition_new
+ * @see elm_box_layout_transition
+ *
+ * @ingroup Box
+ */
+EAPI Elm_Box_Transition *
+elm_box_transition_new(const double duration,
+      Evas_Object_Box_Layout start_layout, void *start_layout_data,
+      void(*start_layout_free_data)(void *data),
+      Evas_Object_Box_Layout end_layout, void *end_layout_data,
+      void(*end_layout_free_data)(void *data),
+      void(*transition_end_cb)(void *data),
+      void *transition_end_data)
+{
+   Elm_Box_Transition *box_data;
+
+   if ((!start_layout) || (!end_layout))
+      return NULL;
+
+   box_data = calloc(1, sizeof(Elm_Box_Transition));
+   if (!box_data)
+      return NULL;
+
+   box_data->start.layout = start_layout;
+   box_data->start.data = start_layout_data;
+   box_data->start.free_data = start_layout_free_data;
+   box_data->end.layout = end_layout;
+   box_data->end.data = end_layout_data;
+   box_data->end.free_data = end_layout_free_data;
+   box_data->duration = duration;
+   box_data->transition_end_cb = transition_end_cb;
+   box_data->transition_end_data = transition_end_data;
+   return box_data;
+}
+
+/**
+ * Free a Elm_Box_Transition instance created with elm_box_transition_new().
+ *
+ * @param data The Elm_Box_Transition instance to be freed.
+ *
+ * @see elm_box_transition_new
+ * @see elm_box_layout_transition
+ *
+ * @ingroup Box
+ */
+EAPI void
+elm_box_transition_free(void *data)
+{
+   Transition_Animation_Data *tad;
+   Elm_Box_Transition *box_data = data;
+   if (box_data->start.free_data && box_data->start.data)
+      box_data->start.free_data(box_data->start.data);
+   if (box_data->end.free_data && box_data->end.data)
+      box_data->end.free_data(box_data->end.data);
+   EINA_LIST_FREE(box_data->objs, tad)
+      free(tad);
+   evas_object_event_callback_del(box_data->box, EVAS_CALLBACK_RESIZE, _transition_layout_obj_resize_cb);
+   evas_object_smart_callback_del(box_data->box, SIG_CHILD_ADDED, _transition_layout_child_added);
+   evas_object_smart_callback_del(box_data->box, SIG_CHILD_REMOVED, _transition_layout_child_removed);
+   if (box_data->animator)
+     {
+        ecore_animator_del(box_data->animator);
+        box_data->animator = NULL;
+     }
+   free(data);
+}
------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to