2010/9/22 Gustavo Sverzut Barbieri <[email protected]>:
> 2010/9/22 Otávio Pontes <[email protected]>:
>> I have added the transition layout into edje too. It displays an
>> animation when changing box state with different layouts.
>> I am sending the patch for edje and an edc sample file.
>
> Awesome results, few comments:
>
>  - edje users don't have direct access to items, so you shouldn't
> require to listen to child,added/child,removed... but it doesn't
> hurt...  however:
>
>  - edje already knows about the items, as they are managed through
> edje_object_part_box_* methods. You should reuse that. This will avoid
> reload children list to recreate all items again.

Done. And it was a better solution.

>
>  - at _edje_box_layout_calculate_coords() you don't revert the box
> properties (padding, align) to the original once you measure the final
> state. Okay, at layout you have a "if (progress == 0.0)" and then do
> that, but it is better to do it in the other function. Also, comparing

Setting box properties in layout function when progress == 0 is
necessary because sometimes layout is used without any animation and
_edje_box_layout_calculate_coords is called only when an animation
will start. After running _edje_box_layout_calculate_coords the layout
will place objects without looking at box properties. These properties
will be needed only when progress == 0.0, so setting them on
_edje_box_layout_calculate_coords is not necessary.

> for double equality will raise some warnings for compilers with
> -Wextra AFAIR.
>

Checking now if progress < 0.01 to avoid floating point problems.

>  - double check if anim->start_progress < 1 before calling _exec() to
> avoid division by 0.0 and an FPU exception? While it is hard to happen
> in tests, it may happen one day in platforms that crash the
> application :-(

Done.

>
>  - edje coding style require all structs with Edje prefix, even if
> they are private.
>

Done

>
> Last but not least, few questions that I cannot remember from Edje and
> from your patch it is not obvious to me:
>
>   - does it still allocates the animation even if the transition is
> immediate (ie: zero timed "transition:" in your program)? Seems so as
> _edje_box_recalc_apply() always create it.

_edje_box_recalc_apply aways allocate the anim struct, that is used
for all animations with this box. I could allocate the struct only if
necessary, but it wont be possible to avoid reloading children in
_edje_box_layout_load_children_list. In this new patch anim struct is
created when the first child is added to the box.

>
>
> I'd move this to part box constructor:
> evas_object_box_layout_set(ep->object, _edje_box_layout, ep->anim,
> _edje_box_layout_free_data), always have it (you may even call it just
> "box" and remove the "anim" reference. Then you free it (your
> _edje_box_layout_free_data) at part delete. You keep this as the
> single layout function ever set to ep->object.  Then move all your
> _edje_box_layout_calculate_coords() to _edje_box_recalc_apply() as
> there you know for sure what happened and do not have to set a flag to
> be checked later... I guess these things will make code simpler and
> less error prone, also easier for others to review and maintain it.

Calling functions to allocate and destroy data in edje_load.c. Restart
flag was removed and   _edje_box_layout_calculate_coords is called in
in _edje_box_recalc_apply. The recalculate flag is still necessary.

Sending new patch attached.

>
> Good work so far!
>
>
> --
> Gustavo Sverzut Barbieri
> http://profusion.mobi embedded systems
> --------------------------------------
> MSN: [email protected]
> Skype: gsbarbieri
> Mobile: +55 (19) 9225-2202
>
From 9fa81fd7b8b747f9ed774c61858f2b3265a209f0 Mon Sep 17 00:00:00 2001
From: Otavio Pontes <[email protected]>
Date: Mon, 20 Sep 2010 17:34:53 -0300
Subject: [PATCH] Adding a transition layout animation for edje box.
To: [email protected]

Perform an animation when changing the layout from an edje box.
---
 edje/src/lib/Makefile.am       |    1 +
 edje/src/lib/edje_box_layout.c |  231 ++++++++++++++++++++++++++++++++++++++++
 edje/src/lib/edje_calc.c       |   37 -------
 edje/src/lib/edje_load.c       |    6 +
 edje/src/lib/edje_private.h    |    7 ++
 edje/src/lib/edje_util.c       |   27 +++++
 6 files changed, 272 insertions(+), 37 deletions(-)
 create mode 100644 edje/src/lib/edje_box_layout.c

diff --git a/edje/src/lib/Makefile.am b/edje/src/lib/Makefile.am
index b73c96f..10546ff 100644
--- a/edje/src/lib/Makefile.am
+++ b/edje/src/lib/Makefile.am
@@ -20,6 +20,7 @@ includes_HEADERS = Edje.h Edje_Edit.h
 includesdir = $(includedir)/ed...@vmaj@
 
 base_sources = \
+edje_box_layout.c \
 edje_calc.c \
 edje_callbacks.c \
 edje_data.c \
diff --git a/edje/src/lib/edje_box_layout.c b/edje/src/lib/edje_box_layout.c
new file mode 100644
index 0000000..d5aaa27
--- /dev/null
+++ b/edje/src/lib/edje_box_layout.c
@@ -0,0 +1,231 @@
+#include "edje_private.h"
+
+typedef struct _Edje_Transition_Animation_Data Edje_Transition_Animation_Data;
+struct _Edje_Transition_Animation_Data
+{
+   Evas_Object *obj;
+   struct
+   {
+      Evas_Coord x, y, w, h;
+   } start, end;
+};
+
+struct _Edje_Part_Box_Animation
+{
+   struct
+   {
+      Evas_Object_Box_Layout layout;
+      void *data;
+      void(*free_data)(void *data);
+      Edje_Alignment align;
+      Evas_Point padding;
+   } start, end;
+   Eina_List *objs;
+   Eina_Bool recalculate:1;
+   Evas_Object *box;
+   double progress;
+   double start_progress;
+   int box_start_w, box_start_h;
+};
+
+static void
+_edje_box_layout_find_all(const char *name, const char *name_alt, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data))
+{
+   if (!_edje_box_layout_find(name, cb, data, free_data))
+     {
+        if ((!name_alt) ||
+            (!_edje_box_layout_find(name_alt, cb, data, free_data)))
+          {
+             ERR("box layout '%s' (fallback '%s') not available, using horizontal.",
+                 name, name_alt);
+             *cb = evas_object_box_layout_horizontal;
+             *free_data = NULL;
+             *data = NULL;
+          }
+     }
+}
+
+static void
+_edje_box_layout_calculate_coords(Evas_Object *obj, Evas_Object_Box_Data *priv, Edje_Part_Box_Animation *anim)
+{
+   Eina_List *l;
+   Edje_Transition_Animation_Data *tad;
+   Evas_Coord x, y;
+
+   evas_object_geometry_get(obj, &x, &y, &anim->box_start_w, &anim->box_start_h);
+   EINA_LIST_FOREACH(anim->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;
+     }
+   evas_object_box_padding_set(obj, anim->end.padding.x, anim->end.padding.y);
+   evas_object_box_align_set(obj, TO_DOUBLE(anim->end.align.x), TO_DOUBLE(anim->end.align.y));
+   anim->end.layout(obj, priv, anim->end.data);
+   EINA_LIST_FOREACH(anim->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 void
+_edje_box_layout_exec(Evas_Object *obj, Edje_Part_Box_Animation *anim)
+{
+   Eina_List *l;
+   Edje_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 = (anim->progress - anim->start_progress) / (1 - anim->start_progress);
+
+   EINA_LIST_FOREACH(anim->objs, l, tad)
+     {
+        cur_x = x + (tad->start.x + ((tad->end.x - tad->start.x) * progress)) * (w / (double)anim->box_start_w);
+        cur_y = y + (tad->start.y + ((tad->end.y - tad->start.y) * progress)) * (h / (double)anim->box_start_h);
+        cur_w = (w / (double)anim->box_start_w) * (tad->start.w + ((tad->end.w - tad->start.w) * progress));
+        cur_h = (h / (double)anim->box_start_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);
+     }
+}
+
+static void
+_edje_box_layout(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data)
+{
+   Edje_Part_Box_Animation *anim = data;
+   if (anim->progress < 0.01)
+     {
+        evas_object_box_padding_set(obj, anim->start.padding.x, anim->start.padding.y);
+        evas_object_box_align_set(obj, TO_DOUBLE(anim->start.align.x), TO_DOUBLE(anim->start.align.y));
+        anim->start.layout(obj, priv, anim->start.data);
+        return;
+     }
+
+   if (anim->recalculate)
+     {
+        _edje_box_layout_calculate_coords(obj, priv, anim);
+        anim->start_progress = anim->progress;
+        anim->recalculate = EINA_FALSE;
+     }
+
+   if ((anim->progress > 0) && (anim->start_progress < 1))
+      _edje_box_layout_exec(obj, anim);
+}
+
+void
+_edje_box_layout_free_data(void *data)
+{
+   Edje_Transition_Animation_Data *tad;
+   Edje_Part_Box_Animation *anim = data;
+   if (anim->start.free_data && anim->start.data)
+      anim->start.free_data(anim->start.data);
+   if (anim->end.free_data && anim->end.data)
+      anim->end.free_data(anim->end.data);
+   EINA_LIST_FREE(anim->objs, tad)
+      free(tad);
+   free(data);
+}
+
+Edje_Part_Box_Animation *
+_edje_box_layout_anim_new(Evas_Object *box)
+{
+   Edje_Part_Box_Animation *anim = calloc(1, sizeof(Edje_Part_Box_Animation));
+   if (!anim)
+      return NULL;
+
+   anim->box = box;
+   evas_object_box_layout_set(box, _edje_box_layout, anim, NULL);
+
+   return anim;
+}
+
+void
+_edje_box_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description_Box *chosen_desc)
+{
+   Evas_Object_Box_Data *priv;
+   int min_w, min_h;
+   if ((ep->param2) && (ep->description_pos != ZERO))
+     {
+        Edje_Part_Description_Box *param2_desc = (Edje_Part_Description_Box *)ep->param2->description;
+        if (ep->anim->end.layout == NULL)
+          {
+             _edje_box_layout_find_all(param2_desc->box.layout, param2_desc->box.alt_layout, &ep->anim->end.layout, &ep->anim->end.data, &ep->anim->end.free_data);
+             ep->anim->end.padding.x = param2_desc->box.padding.x;
+             ep->anim->end.padding.y = param2_desc->box.padding.y;
+             ep->anim->end.align.x = param2_desc->box.align.x;
+             ep->anim->end.align.y = param2_desc->box.align.y;
+
+             priv = evas_object_smart_data_get(ep->object);
+             if (priv == NULL)
+                return;
+
+             evas_object_box_padding_set(ep->object, ep->anim->start.padding.x, ep->anim->start.padding.y);
+             evas_object_box_align_set(ep->object, TO_DOUBLE(ep->anim->start.align.x), TO_DOUBLE(ep->anim->start.align.y));
+             ep->anim->start.layout(ep->object, priv, ep->anim->start.data);
+             _edje_box_layout_calculate_coords(ep->object, priv, ep->anim);
+             ep->anim->start_progress = 0.0;
+          }
+        evas_object_smart_changed(ep->object);
+     }
+   else {
+      ep->anim->end.layout = NULL;
+   }
+
+   if (ep->description_pos < 0.01 || !ep->anim->start.layout)
+     {
+        _edje_box_layout_find_all(chosen_desc->box.layout, chosen_desc->box.alt_layout, &ep->anim->start.layout, &ep->anim->start.data, &ep->anim->start.free_data);
+        ep->anim->start.padding.x = chosen_desc->box.padding.x;
+        ep->anim->start.padding.y = chosen_desc->box.padding.y;
+        ep->anim->start.align.x = chosen_desc->box.align.x;
+        ep->anim->start.align.y = chosen_desc->box.align.y;
+        evas_object_smart_changed(ep->object);
+     }
+
+   ep->anim->progress = ep->description_pos;
+
+   if (evas_object_smart_need_recalculate_get(ep->object))
+     {
+	evas_object_smart_need_recalculate_set(ep->object, 0);
+	evas_object_smart_calculate(ep->object);
+     }
+   evas_object_size_hint_min_get(ep->object, &min_w, &min_h);
+   if (chosen_desc->box.min.h && (p3->w < min_w))
+     p3->w = min_w;
+   if (chosen_desc->box.min.v && (p3->h < min_h))
+     p3->h = min_h;
+}
+
+Eina_Bool
+_edje_box_layout_add_child(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   Edje_Transition_Animation_Data *tad;
+   tad = calloc(1, sizeof(Edje_Transition_Animation_Data));
+   if (!tad)
+      return EINA_FALSE;
+   tad->obj = child_obj;
+   rp->anim->objs = eina_list_append(rp->anim->objs, tad);
+   rp->anim->recalculate = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+void
+_edje_box_layout_remove_child(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   Eina_List *l;
+   Edje_Transition_Animation_Data *tad;
+
+   EINA_LIST_FOREACH(rp->anim->objs, l, tad)
+     {
+        if (tad->obj == child_obj)
+          {
+             free(eina_list_data_get(l));
+             rp->anim->objs = eina_list_remove_list(rp->anim->objs, l);
+             rp->anim->recalculate = EINA_TRUE;
+          }
+     }
+   rp->anim->recalculate = EINA_TRUE;
+}
diff --git a/edje/src/lib/edje_calc.c b/edje/src/lib/edje_calc.c
index 364c7a5..958ab60 100644
--- a/edje/src/lib/edje_calc.c
+++ b/edje/src/lib/edje_calc.c
@@ -1423,43 +1423,6 @@ _edje_part_recalc_single(Edje *ed,
 }
 
 static void
-_edje_box_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description_Box *chosen_desc)
-{
-   Evas_Object_Box_Layout layout;
-   void (*free_data)(void *data);
-   void *data;
-   int min_w, min_h;
-
-   if (!_edje_box_layout_find(chosen_desc->box.layout, &layout, &data, &free_data))
-     {
-	if ((!chosen_desc->box.alt_layout) ||
-	    (!_edje_box_layout_find(chosen_desc->box.alt_layout, &layout, &data, &free_data)))
-	  {
-	     ERR("box layout '%s' (fallback '%s') not available, using horizontal.",
-		 chosen_desc->box.layout, chosen_desc->box.alt_layout);
-	     layout = evas_object_box_layout_horizontal;
-	     free_data = NULL;
-	     data = NULL;
-	  }
-     }
-
-   evas_object_box_layout_set(ep->object, layout, data, free_data);
-   evas_object_box_align_set(ep->object, TO_DOUBLE(chosen_desc->box.align.x), TO_DOUBLE(chosen_desc->box.align.y));
-   evas_object_box_padding_set(ep->object, chosen_desc->box.padding.x, chosen_desc->box.padding.y);
-
-   if (evas_object_smart_need_recalculate_get(ep->object))
-     {
-	evas_object_smart_need_recalculate_set(ep->object, 0);
-	evas_object_smart_calculate(ep->object);
-     }
-   evas_object_size_hint_min_get(ep->object, &min_w, &min_h);
-   if (chosen_desc->box.min.h && (p3->w < min_w))
-     p3->w = min_w;
-   if (chosen_desc->box.min.v && (p3->h < min_h))
-     p3->h = min_h;
-}
-
-static void
 _edje_table_recalc_apply(Edje *ed __UNUSED__,
 			 Edje_Real_Part *ep,
 			 Edje_Calc_Params *p3 __UNUSED__,
diff --git a/edje/src/lib/edje_load.c b/edje/src/lib/edje_load.c
index 325af02..9894cb2 100644
--- a/edje/src/lib/edje_load.c
+++ b/edje/src/lib/edje_load.c
@@ -457,6 +457,7 @@ _edje_object_file_set_internal(Evas_Object *obj, const char *file, const char *g
 			break;
 		     case EDJE_PART_TYPE_BOX:
 			rp->object = evas_object_box_add(ed->evas);
+                        rp->anim = _edje_box_layout_anim_new(rp->object);
 			break;
 		     case EDJE_PART_TYPE_TABLE:
 			rp->object = evas_object_table_add(ed->evas);
@@ -973,6 +974,11 @@ _edje_file_del(Edje *ed)
 		  /* evas_box/table handles deletion of objects */
 		  rp->items = eina_list_free(rp->items);
 	       }
+             if (rp->anim)
+               {
+                  _edje_box_layout_free_data(rp->anim);
+                  rp->anim = NULL;
+               }
 	     if (rp->text.text) eina_stringshare_del(rp->text.text);
 	     if (rp->text.font) eina_stringshare_del(rp->text.font);
 	     if (rp->text.cache.in_str) eina_stringshare_del(rp->text.cache.in_str);
diff --git a/edje/src/lib/edje_private.h b/edje/src/lib/edje_private.h
index 8ffc141..f602072 100644
--- a/edje/src/lib/edje_private.h
+++ b/edje/src/lib/edje_private.h
@@ -269,6 +269,7 @@ typedef struct _Edje_Part_Description_Spec_Text      Edje_Part_Description_Spec_
 typedef struct _Edje_Part_Description_Spec_Box       Edje_Part_Description_Spec_Box;
 typedef struct _Edje_Part_Description_Spec_Table     Edje_Part_Description_Spec_Table;
 typedef struct _Edje_Patterns                        Edje_Patterns;
+typedef struct _Edje_Part_Box_Animation              Edje_Part_Box_Animation;
 
 #define EDJE_INF_MAX_W 100000
 #define EDJE_INF_MAX_H 100000
@@ -1088,6 +1089,7 @@ struct _Edje_Real_Part
    Edje_Rectangle            req; // 16
 
    Eina_List                *items; // 4 //FIXME: only if table/box
+   Edje_Part_Box_Animation  *anim; // 4 //FIXME: Used only if box
    void                     *entry_data; // 4 // FIXME: move to entry section
    Evas_Object              *cursorbg_object; // 4 // FIXME: move to entry section
    Evas_Object              *cursorfg_object; // 4 // FIXME: move to entry section
@@ -1499,6 +1501,11 @@ void              _edje_real_part_swallow_clear(Edje_Real_Part *rp);
 void              _edje_box_init(void);
 void              _edje_box_shutdown(void);
 Eina_Bool         _edje_box_layout_find(const char *name, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data));
+void              _edje_box_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description_Box *chosen_desc);
+Eina_Bool         _edje_box_layout_add_child(Edje_Real_Part *rp, Evas_Object *child_obj);
+void              _edje_box_layout_remove_child(Edje_Real_Part *rp, Evas_Object *child_obj);
+Edje_Part_Box_Animation * _edje_box_layout_anim_new(Evas_Object *box);
+void              _edje_box_layout_free_data(void *data);
 
 Eina_Bool         _edje_real_part_box_append(Edje_Real_Part *rp, Evas_Object *child_obj);
 Eina_Bool         _edje_real_part_box_prepend(Edje_Real_Part *rp, Evas_Object *child_obj);
diff --git a/edje/src/lib/edje_util.c b/edje/src/lib/edje_util.c
index 994eb92..d0995de 100644
--- a/edje/src/lib/edje_util.c
+++ b/edje/src/lib/edje_util.c
@@ -3681,6 +3681,12 @@ _edje_real_part_box_append(Edje_Real_Part *rp, Evas_Object *child_obj)
    opt = evas_object_box_append(rp->object, child_obj);
    if (!opt) return EINA_FALSE;
 
+   if (!_edje_box_layout_add_child(rp, child_obj))
+     {
+        evas_object_box_remove(rp->object, child_obj);
+        return EINA_FALSE;
+     }
+
    _edje_box_child_add(rp, child_obj);
 
    return EINA_TRUE;
@@ -3694,6 +3700,12 @@ _edje_real_part_box_prepend(Edje_Real_Part *rp, Evas_Object *child_obj)
    opt = evas_object_box_prepend(rp->object, child_obj);
    if (!opt) return EINA_FALSE;
 
+   if (!_edje_box_layout_add_child(rp, child_obj))
+     {
+        evas_object_box_remove(rp->object, child_obj);
+        return EINA_FALSE;
+     }
+
    _edje_box_child_add(rp, child_obj);
 
    return EINA_TRUE;
@@ -3707,6 +3719,12 @@ _edje_real_part_box_insert_before(Edje_Real_Part *rp, Evas_Object *child_obj, co
    opt = evas_object_box_insert_before(rp->object, child_obj, ref);
    if (!opt) return EINA_FALSE;
 
+   if (!_edje_box_layout_add_child(rp, child_obj))
+     {
+        evas_object_box_remove(rp->object, child_obj);
+        return EINA_FALSE;
+     }
+
    _edje_box_child_add(rp, child_obj);
 
    return EINA_TRUE;
@@ -3720,6 +3738,12 @@ _edje_real_part_box_insert_at(Edje_Real_Part *rp, Evas_Object *child_obj, unsign
    opt = evas_object_box_insert_at(rp->object, child_obj, pos);
    if (!opt) return EINA_FALSE;
 
+   if (!_edje_box_layout_add_child(rp, child_obj))
+     {
+        evas_object_box_remove(rp->object, child_obj);
+        return EINA_FALSE;
+     }
+
    _edje_box_child_add(rp, child_obj);
 
    return EINA_TRUE;
@@ -3730,6 +3754,7 @@ _edje_real_part_box_remove(Edje_Real_Part *rp, Evas_Object *child_obj)
 {
    if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
    if (!evas_object_box_remove(rp->object, child_obj)) return NULL;
+   _edje_box_layout_remove_child(rp, child_obj);
    _edje_box_child_remove(rp, child_obj);
    return child_obj;
 }
@@ -3747,6 +3772,7 @@ _edje_real_part_box_remove_at(Edje_Real_Part *rp, unsigned int pos)
    child_obj = opt->obj;
    if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
    if (!evas_object_box_remove_at(rp->object, pos)) return NULL;
+   _edje_box_layout_remove_child(rp, child_obj);
    _edje_box_child_remove(rp, child_obj);
    return child_obj;
 }
@@ -3765,6 +3791,7 @@ _edje_real_part_box_remove_all(Edje_Real_Part *rp, Eina_Bool clear)
 	  i++;
 	else
 	  {
+             _edje_box_layout_remove_child(rp, child_obj);
 	     _edje_box_child_remove(rp, child_obj);
 	     if (!evas_object_box_remove_at(rp->object, i))
 	       return EINA_FALSE;
-- 
1.7.2.3

------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in  U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store 
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to