Imported Upstream version 1.7.1
[platform/upstream/edje.git] / src / lib / edje_box_layout.c
1 #include "edje_private.h"
2
3 typedef struct _Edje_Transition_Animation_Data Edje_Transition_Animation_Data;
4 struct _Edje_Transition_Animation_Data
5 {
6    Evas_Object *obj;
7    struct
8    {
9       Evas_Coord x, y, w, h;
10    } start, end;
11 };
12
13 struct _Edje_Part_Box_Animation
14 {
15    struct
16    {
17       Evas_Object_Box_Layout layout;
18       void *data;
19       void(*free_data)(void *data);
20       Edje_Alignment align;
21       Evas_Point padding;
22    } start, end;
23    Eina_List *objs;
24    Eina_Bool recalculate:1;
25    Evas_Object *box;
26    double progress;
27    double start_progress;
28    int box_start_w, box_start_h;
29 };
30
31 static void
32 _edje_box_layout_find_all(const char *name, const char *name_alt, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data))
33 {
34    if (!_edje_box_layout_find(name, cb, data, free_data))
35      {
36         if ((!name_alt) ||
37             (!_edje_box_layout_find(name_alt, cb, data, free_data)))
38           {
39              ERR("box layout '%s' (fallback '%s') not available, using horizontal.",
40                  name, name_alt);
41              *cb = evas_object_box_layout_horizontal;
42              *free_data = NULL;
43              *data = NULL;
44           }
45      }
46 }
47
48 static void
49 _edje_box_layout_calculate_coords(Evas_Object *obj, Evas_Object_Box_Data *priv, Edje_Part_Box_Animation *anim)
50 {
51    Eina_List *l;
52    Edje_Transition_Animation_Data *tad;
53    Evas_Coord x, y;
54
55    evas_object_geometry_get(obj, &x, &y, &anim->box_start_w, &anim->box_start_h);
56    EINA_LIST_FOREACH(anim->objs, l, tad)
57      {
58         evas_object_geometry_get(tad->obj, &tad->start.x, &tad->start.y,
59               &tad->start.w, &tad->start.h);
60         tad->start.x = tad->start.x - x;
61         tad->start.y = tad->start.y - y;
62      }
63    evas_object_box_padding_set(obj, anim->end.padding.x, anim->end.padding.y);
64    evas_object_box_align_set(obj, TO_DOUBLE(anim->end.align.x), TO_DOUBLE(anim->end.align.y));
65    anim->end.layout(obj, priv, anim->end.data);
66    EINA_LIST_FOREACH(anim->objs, l, tad)
67      {
68         evas_object_geometry_get(tad->obj, &tad->end.x, &tad->end.y,
69               &tad->end.w, &tad->end.h);
70         tad->end.x = tad->end.x - x;
71         tad->end.y = tad->end.y - y;
72      }
73 }
74
75 static void
76 _edje_box_layout_exec(Evas_Object *obj, Edje_Part_Box_Animation *anim)
77 {
78    Eina_List *l;
79    Edje_Transition_Animation_Data *tad;
80    Evas_Coord x, y, w, h;
81    Evas_Coord cur_x, cur_y, cur_w, cur_h;
82    double progress;
83
84    evas_object_geometry_get(obj, &x, &y, &w, &h);
85    progress = (anim->progress - anim->start_progress) / (1 - anim->start_progress);
86
87    EINA_LIST_FOREACH(anim->objs, l, tad)
88      {
89         cur_x = x + (tad->start.x + ((tad->end.x - tad->start.x) * progress)) * (w / (double)anim->box_start_w);
90         cur_y = y + (tad->start.y + ((tad->end.y - tad->start.y) * progress)) * (h / (double)anim->box_start_h);
91         cur_w = (w / (double)anim->box_start_w) * (tad->start.w + ((tad->end.w - tad->start.w) * progress));
92         cur_h = (h / (double)anim->box_start_h) * (tad->start.h + ((tad->end.h - tad->start.h) * progress));
93         evas_object_move(tad->obj, cur_x, cur_y);
94         evas_object_resize(tad->obj, cur_w, cur_h);
95      }
96 }
97
98 static void
99 _edje_box_layout(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data)
100 {
101    Edje_Part_Box_Animation *anim = data;
102    if (anim->progress < 0.01)
103      {
104         if (anim->start.layout)
105           {
106              evas_object_box_padding_set(obj, anim->start.padding.x, anim->start.padding.y);
107              evas_object_box_align_set(obj, TO_DOUBLE(anim->start.align.x), TO_DOUBLE(anim->start.align.y));
108              anim->start.layout(obj, priv, anim->start.data);
109           }
110         return;
111      }
112
113    if (anim->recalculate)
114      {
115         _edje_box_layout_calculate_coords(obj, priv, anim);
116         anim->start_progress = anim->progress;
117         anim->recalculate = EINA_FALSE;
118      }
119
120    if ((anim->progress > 0) && (anim->start_progress < 1))
121       _edje_box_layout_exec(obj, anim);
122 }
123
124 void
125 _edje_box_layout_free_data(void *data)
126 {
127    Edje_Transition_Animation_Data *tad;
128    Edje_Part_Box_Animation *anim = data;
129    if (anim->start.free_data && anim->start.data)
130       anim->start.free_data(anim->start.data);
131    if (anim->end.free_data && anim->end.data)
132       anim->end.free_data(anim->end.data);
133    EINA_LIST_FREE(anim->objs, tad)
134       free(tad);
135    free(data);
136 }
137
138 Edje_Part_Box_Animation *
139 _edje_box_layout_anim_new(Evas_Object *box)
140 {
141    Edje_Part_Box_Animation *anim = calloc(1, sizeof(Edje_Part_Box_Animation));
142    if (!anim)
143       return NULL;
144
145    anim->box = box;
146    evas_object_box_layout_set(box, _edje_box_layout, anim, NULL);
147
148    return anim;
149 }
150
151 void
152 _edje_box_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3 __UNUSED__, Edje_Part_Description_Box *chosen_desc)
153 {
154    Evas_Object_Box_Data *priv;
155 #if 0
156    int min_w, min_h;
157 #endif
158    if ((ep->param2) && (ep->description_pos != ZERO))
159      {
160         Edje_Part_Description_Box *param2_desc = (Edje_Part_Description_Box *)ep->param2->description;
161         if (ep->anim->end.layout == NULL)
162           {
163              _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);
164              ep->anim->end.padding.x = param2_desc->box.padding.x;
165              ep->anim->end.padding.y = param2_desc->box.padding.y;
166              ep->anim->end.align.x = param2_desc->box.align.x;
167              ep->anim->end.align.y = param2_desc->box.align.y;
168
169              priv = evas_object_smart_data_get(ep->object);
170              if (priv == NULL)
171                 return;
172
173              evas_object_box_padding_set(ep->object, ep->anim->start.padding.x, ep->anim->start.padding.y);
174              evas_object_box_align_set(ep->object, TO_DOUBLE(ep->anim->start.align.x), TO_DOUBLE(ep->anim->start.align.y));
175              ep->anim->start.layout(ep->object, priv, ep->anim->start.data);
176              _edje_box_layout_calculate_coords(ep->object, priv, ep->anim);
177              ep->anim->start_progress = 0.0;
178           }
179         evas_object_smart_changed(ep->object);
180      }
181    else
182      {
183         ep->anim->end.layout = NULL;
184      }
185
186    if (ep->description_pos < 0.01 || !ep->anim->start.layout)
187      {
188         _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);
189         ep->anim->start.padding.x = chosen_desc->box.padding.x;
190         ep->anim->start.padding.y = chosen_desc->box.padding.y;
191         ep->anim->start.align.x = chosen_desc->box.align.x;
192         ep->anim->start.align.y = chosen_desc->box.align.y;
193         evas_object_smart_changed(ep->object);
194      }
195
196    ep->anim->progress = ep->description_pos;
197
198    if (evas_object_smart_need_recalculate_get(ep->object))
199      {
200         evas_object_smart_need_recalculate_set(ep->object, 0);
201         evas_object_smart_calculate(ep->object);
202      }
203 #if 0 /* Why the hell do we affect part size after resize ??? */
204    evas_object_size_hint_min_get(ep->object, &min_w, &min_h);
205    if (chosen_desc->box.min.h && (p3->w < min_w))
206      p3->w = min_w;
207    if (chosen_desc->box.min.v && (p3->h < min_h))
208      p3->h = min_h;
209 #endif
210 }
211
212 Eina_Bool
213 _edje_box_layout_add_child(Edje_Real_Part *rp, Evas_Object *child_obj)
214 {
215    Edje_Transition_Animation_Data *tad;
216    tad = calloc(1, sizeof(Edje_Transition_Animation_Data));
217    if (!tad)
218       return EINA_FALSE;
219    tad->obj = child_obj;
220    rp->anim->objs = eina_list_append(rp->anim->objs, tad);
221    rp->anim->recalculate = EINA_TRUE;
222    return EINA_TRUE;
223 }
224
225 void
226 _edje_box_layout_remove_child(Edje_Real_Part *rp, Evas_Object *child_obj)
227 {
228    Eina_List *l;
229    Edje_Transition_Animation_Data *tad;
230
231    EINA_LIST_FOREACH(rp->anim->objs, l, tad)
232      {
233         if (tad->obj == child_obj)
234           {
235              free(eina_list_data_get(l));
236              rp->anim->objs = eina_list_remove_list(rp->anim->objs, l);
237              rp->anim->recalculate = EINA_TRUE;
238              break;
239           }
240      }
241    rp->anim->recalculate = EINA_TRUE;
242 }