================================================================
[framework/uifw/elementary.git] / src / lib / elm_flip.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Flip Flip
6  * @ingroup Elementary
7  *
8  * This holds 2 content objects: one on the front and one on the back. It
9  * allows you to flip from front to back and vice-versa using various effects.
10  *
11  * Supported flip types:
12  * ELM_FLIP_ROTATE_Y_CENTER_AXIS
13  * ELM_FLIP_ROTATE_X_CENTER_AXIS
14  * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
15  * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
16  *
17  * Signals that you can add callbacks for are:
18  *
19  * "animate,done" - when a flip animation is finished
20  */
21
22 typedef struct _Widget_Data Widget_Data;
23
24 struct _Widget_Data
25 {
26    Ecore_Animator *animator;
27    double start, len;
28    Elm_Flip_Mode mode;
29    Evas_Object *clip;
30    struct {
31       Evas_Object *content, *clip;
32    } front, back;
33    Eina_Bool state : 1;
34 };
35
36 static const char *widtype = NULL;
37 static void _del_hook(Evas_Object *obj);
38 static void _theme_hook(Evas_Object *obj);
39 static void _sizing_eval(Evas_Object *obj);
40 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
41 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
42
43 static void _configure(Evas_Object *obj);
44
45 static void
46 _del_hook(Evas_Object *obj)
47 {
48    Widget_Data *wd = elm_widget_data_get(obj);
49    if (!wd) return;
50    if (wd->animator) ecore_animator_del(wd->animator);
51    free(wd);
52 }
53
54 static void
55 _theme_hook(Evas_Object *obj)
56 {
57    Widget_Data *wd = elm_widget_data_get(obj);
58    if (!wd) return;
59    _sizing_eval(obj);
60 }
61
62 static Eina_Bool
63 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
64 {
65    Widget_Data *wd = elm_widget_data_get(obj);
66
67    if (!wd)
68      return EINA_FALSE;
69
70    /* Try Focus cycle in subitem */
71    if (wd->state)
72      return elm_widget_focus_next_get(wd->front.content, dir, next);
73    else
74      return elm_widget_focus_next_get(wd->back.content, dir, next);
75
76 }
77
78 static void
79 _sizing_eval(Evas_Object *obj)
80 {
81    Widget_Data *wd = elm_widget_data_get(obj);
82    Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
83    Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
84    if (!wd) return;
85    if (wd->front.content)
86      evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
87    if (wd->back.content)
88      evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
89    if (wd->front.content)
90      evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
91    if (wd->back.content)
92      evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
93    
94    if (minw2 > minw) minw = minw2;
95    if (minh2 > minh) minh = minh2;
96    if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
97    if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
98    
99    evas_object_size_hint_min_set(obj, minw, minh);
100    evas_object_size_hint_max_set(obj, maxw, maxh);
101 }
102
103 static void
104 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
105 {
106    Widget_Data *wd = elm_widget_data_get(data);
107    if (!wd) return;
108    _sizing_eval(data);
109 }
110
111 static void
112 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
113 {
114    Widget_Data *wd = elm_widget_data_get(obj);
115    Evas_Object *sub = event_info;
116    if (!wd) return;
117    if (sub == wd->front.content)
118      {
119         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
120                                             _changed_size_hints, obj);
121         wd->front.content = NULL;
122         evas_object_hide(wd->front.clip);
123         _sizing_eval(obj);
124      }
125    else if (sub == wd->back.content)
126      {
127         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
128                                             _changed_size_hints, obj);
129         wd->back.content = NULL;
130         evas_object_hide(wd->back.clip);
131         _sizing_eval(obj);
132      }
133 }
134
135 static void
136 flip_show_hide(Evas_Object *obj)
137 {
138    Widget_Data *wd = elm_widget_data_get(obj);
139    if (elm_flip_front_get(obj))
140      {
141         if (wd->front.content)
142            evas_object_show(wd->front.clip);
143         else
144            evas_object_hide(wd->front.clip);
145         if (wd->back.content)
146            evas_object_hide(wd->back.clip);
147         else
148            evas_object_hide(wd->back.clip);
149      }
150    else
151      {
152         if (wd->front.content)
153            evas_object_hide(wd->front.clip);
154         else
155            evas_object_hide(wd->front.clip);
156         if (wd->back.content)
157            evas_object_show(wd->back.clip);
158         else
159            evas_object_hide(wd->back.clip);
160      }
161 }
162
163 static Eina_Bool
164 _flip(Evas_Object *obj)
165 {
166    Widget_Data *wd = elm_widget_data_get(obj);
167    double t = ecore_loop_time_get() - wd->start;
168    Evas_Coord x, y, w, h;
169    double p, deg;
170    Evas_Map *mf, *mb;
171    Evas_Coord cx, cy, px, py, foc;
172    int lx, ly, lz, lr, lg, lb, lar, lag, lab;
173    if (!wd->animator) return ECORE_CALLBACK_CANCEL;
174    t = t / wd->len;
175    if (t > 1.0) t = 1.0;
176
177    if (!wd) return ECORE_CALLBACK_CANCEL;
178
179    mf = evas_map_new(4);
180    evas_map_smooth_set(mf, 0);
181    mb = evas_map_new(4);
182    evas_map_smooth_set(mb, 0);
183
184    if (wd->front.content)
185      {
186         evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
187         evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
188      }
189    if (wd->back.content)
190      {
191         evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
192         evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
193      }
194    
195    evas_object_geometry_get(obj, &x, &y, &w, &h);
196    
197    cx = x + (w / 2);
198    cy = y + (h / 2);
199
200    px = x + (w / 2);
201    py = y + (h / 2);
202    foc = 2048;
203    
204    lx = cx;
205    ly = cy;
206    lz = -10000;
207    lr = 255;
208    lg = 255;
209    lb = 255;
210    lar = 0;
211    lag = 0;
212    lab = 0;
213    
214    switch (wd->mode)
215      {
216      case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
217         p = 1.0 - t;
218         p = 1.0 - (p * p);
219         if (wd->state) deg = 180.0 * p;
220         else deg = 180 + (180.0 * p);
221         evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
222         evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
223         break;
224      case ELM_FLIP_ROTATE_X_CENTER_AXIS:
225         p = 1.0 - t;
226         p = 1.0 - (p * p);
227         if (wd->state) deg = 180.0 * p;
228         else deg = 180 + (180.0 * p);
229         evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
230         evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
231         break;
232      case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
233         p = 1.0 - t;
234         p = 1.0 - (p * p);
235         if (wd->state) deg = 180.0 * p;
236         else deg = 180 + (180.0 * p);
237         evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
238         evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
239         break;
240      case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
241         p = 1.0 - t;
242         p = 1.0 - (p * p);
243         if (wd->state) deg = 180.0 * p;
244         else deg = 180 + (180.0 * p);
245         evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
246         evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
247         break;
248      case ELM_FLIP_CUBE_LEFT:
249         p = 1.0 - t;
250         p = 1.0 - (p * p);
251         deg = -90.0 * p;
252         if (wd->state)
253           {
254             evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
255             evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
256           }
257         else
258           {
259             evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
260             evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
261           }
262         break;
263      case ELM_FLIP_CUBE_RIGHT:
264         p = 1.0 - t;
265         p = 1.0 - (p * p);
266         deg = 90.0 * p;
267         if (wd->state)
268           {
269             evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
270             evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
271           }
272         else
273           {
274             evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
275             evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
276           }
277         break;
278      case ELM_FLIP_CUBE_UP:
279         p = 1.0 - t;
280         p = 1.0 - (p * p);
281         deg = -90.0 * p;
282         if (wd->state)
283           {
284             evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
285             evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
286           }
287         else
288           {
289             evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
290             evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
291           }
292         break;
293      case ELM_FLIP_CUBE_DOWN:
294         p = 1.0 - t;
295         p = 1.0 - (p * p);
296         deg = 90.0 * p;
297         if (wd->state)
298           {
299             evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
300             evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
301           }
302         else
303           {
304             evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
305             evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
306           }
307         break;
308      default:
309         break;
310      }
311
312    
313    if (wd->front.content)
314      {
315         evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
316         evas_map_util_3d_perspective(mf, px, py, 0, foc);
317         evas_object_map_set(wd->front.content, mf);
318         evas_object_map_enable_set(wd->front.content, 1);
319         if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
320         else evas_object_hide(wd->front.clip);
321      }
322       
323    if (wd->back.content)
324      {
325         evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
326         evas_map_util_3d_perspective(mb, px, py, 0, foc);
327         evas_object_map_set(wd->back.content, mb);
328         evas_object_map_enable_set(wd->back.content, 1);
329         if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
330         else evas_object_hide(wd->back.clip);
331      }
332    
333    evas_map_free(mf);
334    evas_map_free(mb);
335    
336    if (t >= 1.0)
337      {
338         evas_object_map_enable_set(wd->front.content, 0);
339         evas_object_map_enable_set(wd->back.content, 0);
340         // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
341         evas_object_resize(wd->front.content, 0, 0);
342         evas_object_resize(wd->back.content, 0, 0);
343         evas_smart_objects_calculate(evas_object_evas_get(obj));
344         // FIXME: end hack
345         wd->animator = NULL;
346         wd->state = !wd->state;
347         _configure(obj);
348         evas_object_smart_callback_call(obj, "animate,done", NULL);
349         return ECORE_CALLBACK_CANCEL;
350      }
351    return ECORE_CALLBACK_RENEW;
352 }
353
354 static void
355 _configure(Evas_Object *obj)
356 {
357    Widget_Data *wd = elm_widget_data_get(obj);
358    Evas_Coord x, y, w, h;
359    if (!wd) return;
360    evas_object_geometry_get(obj, &x, &y, &w, &h);
361    if (wd->front.content)
362      {
363         if (!wd->animator)
364           evas_object_move(wd->front.content, x, y);
365         evas_object_resize(wd->front.content, w, h);
366      }
367    if (wd->back.content)
368      {
369         if (!wd->animator)
370           evas_object_move(wd->back.content, x, y);
371         evas_object_resize(wd->back.content, w, h);
372      }
373    _flip(obj);
374 }
375
376 static void
377 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
378 {
379    _configure(obj);
380 }
381
382 static void
383 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
384 {    
385    _configure(obj);
386 }
387
388 static Eina_Bool
389 _animate(void *data)
390 {
391    return _flip(data);
392 }
393
394 /**
395  * Add a new flip to the parent
396  *
397  * @param parent The parent object
398  * @return The new object or NULL if it cannot be created
399  *
400  * @ingroup Flip
401  */
402 EAPI Evas_Object *
403 elm_flip_add(Evas_Object *parent)
404 {
405    Evas_Object *obj;
406    Evas *e;
407    Widget_Data *wd;
408
409    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
410
411    wd = ELM_NEW(Widget_Data);
412    e = evas_object_evas_get(parent);
413    if (!e) return NULL;
414    obj = elm_widget_add(e);
415    ELM_SET_WIDTYPE(widtype, "flip");
416    elm_widget_type_set(obj, "flip");
417    elm_widget_sub_object_add(parent, obj);
418    elm_widget_data_set(obj, wd);
419    elm_widget_del_hook_set(obj, _del_hook);
420    elm_widget_theme_hook_set(obj, _theme_hook);
421    elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
422    elm_widget_can_focus_set(obj, EINA_FALSE);
423
424    wd->clip = evas_object_rectangle_add(e);
425    evas_object_static_clip_set(wd->clip, 1);
426    evas_object_color_set(wd->clip, 255, 255, 255, 255);
427    evas_object_move(wd->clip, -49999, -49999);
428    evas_object_resize(wd->clip, 99999, 99999);
429    elm_widget_sub_object_add(obj, wd->clip);
430    evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
431    evas_object_smart_member_add(wd->clip, obj);
432    
433    wd->front.clip = evas_object_rectangle_add(e);
434    evas_object_static_clip_set(wd->front.clip, 1);
435    evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
436    evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
437    evas_object_move(wd->front.clip, -49999, -49999);
438    evas_object_resize(wd->front.clip, 99999, 99999);
439    elm_widget_sub_object_add(obj, wd->front.clip);
440    evas_object_smart_member_add(wd->front.clip, obj);
441    evas_object_clip_set(wd->front.clip, wd->clip);
442    
443    wd->back.clip = evas_object_rectangle_add(e);
444    evas_object_static_clip_set(wd->back.clip, 1);
445    evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
446    evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
447    evas_object_move(wd->back.clip, -49999, -49999);
448    evas_object_resize(wd->back.clip, 99999, 99999);
449    elm_widget_sub_object_add(wd->back.clip, obj);
450    evas_object_smart_member_add(obj, wd->back.clip);
451    evas_object_clip_set(wd->back.clip, wd->clip);
452
453    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
454    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
455    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
456    
457    wd->state = 1;
458      
459    _sizing_eval(obj);
460    return obj;
461 }
462
463 /**
464  * Set the front content of the flip widget.
465  *
466  * Once the content object is set, a previously set one will be deleted.
467  * If you want to keep that old content object, use the
468  * elm_flip_content_front_unset() function.
469  *
470  * @param obj The flip object
471  * @param content The new front content object
472  *
473  * @ingroup Flip
474  */
475 EAPI void
476 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
477 {
478    ELM_CHECK_WIDTYPE(obj, widtype);
479    Widget_Data *wd = elm_widget_data_get(obj);
480    if (!wd) return;
481    if (wd->front.content == content) return;
482    if (wd->front.content) evas_object_del(wd->back.content);
483    wd->front.content = content;
484    if (content)
485      {
486         elm_widget_sub_object_add(obj, content);
487         evas_object_smart_member_add(content, obj);
488         evas_object_clip_set(content, wd->front.clip);
489         evas_object_event_callback_add(content,
490                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
491                                        _changed_size_hints, obj);
492         _sizing_eval(obj);
493      }
494    // force calc to contents are the right size before transition
495    evas_smart_objects_calculate(evas_object_evas_get(obj));
496    flip_show_hide(obj);
497    _configure(obj);
498 }
499
500 /**
501  * Set the back content of the flip widget.
502  *
503  * Once the content object is set, a previously set one will be deleted.
504  * If you want to keep that old content object, use the
505  * elm_flip_content_back_unset() function.
506  *
507  * @param obj The flip object
508  * @param content The new back content object
509  *
510  * @ingroup Flip
511  */
512 EAPI void
513 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
514 {
515    ELM_CHECK_WIDTYPE(obj, widtype);
516    Widget_Data *wd = elm_widget_data_get(obj);
517    if (!wd) return;
518    if (wd->back.content == content) return;
519    if (wd->back.content) evas_object_del(wd->back.content);
520    wd->back.content = content;
521    if (content)
522      {
523         elm_widget_sub_object_add(obj, content);
524         evas_object_smart_member_add(content, obj);
525         evas_object_clip_set(content, wd->back.clip);
526         evas_object_event_callback_add(content,
527                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
528                                        _changed_size_hints, obj);
529         _sizing_eval(obj);
530      }
531    // force calc to contents are the right size before transition
532    evas_smart_objects_calculate(evas_object_evas_get(obj));
533    flip_show_hide(obj);
534    _configure(obj);
535 }
536
537 /**
538  * Get the front content used for the flip
539  *
540  * Return the front content object which is set for this widget.
541  *
542  * @param obj The flip object
543  * @return The front content object that is being used
544  *
545  * @ingroup Flip
546  */
547 EAPI Evas_Object *
548 elm_flip_content_front_get(const Evas_Object *obj)
549 {
550    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
551    Widget_Data *wd = elm_widget_data_get(obj);
552    return wd->front.content;
553 }
554
555
556 /**
557  * Get the back content used for the flip
558  *
559  * Return the back content object which is set for this widget.
560  *
561  * @param obj The flip object
562  * @return The back content object that is being used
563  *
564  * @ingroup Flip
565  */
566 EAPI Evas_Object *
567 elm_flip_content_back_get(const Evas_Object *obj)
568 {
569    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
570    Widget_Data *wd = elm_widget_data_get(obj);
571    return wd->back.content;
572 }
573
574 /**
575  * Unset the front content used for the flip
576  *
577  * Unparent and return the front content object which was set for this widget.
578  *
579  * @param obj The flip object
580  * @return The front content object that was being used
581  *
582  * @ingroup Flip
583  */
584 EAPI Evas_Object *
585 elm_flip_content_front_unset(Evas_Object *obj)
586 {
587    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
588    Widget_Data *wd = elm_widget_data_get(obj);
589    if (!wd) return NULL;
590    if (!wd->front.content) return NULL;
591    Evas_Object *content = wd->front.content;
592    evas_object_clip_unset(content);
593    elm_widget_sub_object_del(obj, content);
594    evas_object_smart_member_del(content);
595    wd->front.content = NULL;
596    return content;
597 }
598
599 /**
600  * Unset the back content used for the flip
601  *
602  * Unparent and return the back content object which was set for this widget.
603  *
604  * @param obj The flip object
605  * @return The back content object that was being used
606  *
607  * @ingroup Flip
608  */
609 EAPI Evas_Object *
610 elm_flip_content_back_unset(Evas_Object *obj)
611 {
612    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
613    Widget_Data *wd = elm_widget_data_get(obj);
614    if (!wd) return NULL;
615    if (!wd->back.content) return NULL;
616    Evas_Object *content = wd->back.content;
617    evas_object_clip_unset(content);
618    elm_widget_sub_object_del(obj, content);
619    evas_object_smart_member_del(content);
620    wd->back.content = NULL;
621    return content;
622 }
623
624 /**
625  * Get flip front visibility state
626  *
627  * @param obj The flip object
628  * @return If front front is showing or not currently
629  *
630  * @ingroup Flip
631  */
632 EAPI Eina_Bool
633 elm_flip_front_get(const Evas_Object *obj)
634 {
635    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
636    Widget_Data *wd = elm_widget_data_get(obj);
637    if (!wd) return EINA_FALSE;
638    return wd->state;
639 }
640
641 /**
642  * Set flip perspective
643  *
644  * @param obj The flip object
645  * @param foc The coordinate to set the focus on
646  * @param x The X coordinate
647  * @param y The Y coordinate
648  *
649  * NOTE: This function currently does nothing.
650  *
651  * @ingroup Flip
652  */
653 EAPI void
654 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
655 {
656    ELM_CHECK_WIDTYPE(obj, widtype);
657    Widget_Data *wd = elm_widget_data_get(obj);
658    if (!wd) return;
659 }
660
661 /**
662  * Runs the flip animation
663  *
664  * @param obj The flip object
665  * @param mode The mode type.  Currently accepted modes are:
666  *
667  * ELM_FLIP_ROTATE_Y_CENTER_AXIS
668  * ELM_FLIP_ROTATE_X_CENTER_AXIS
669  * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
670  * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
671  * ELM_FLIP_CUBE_LEFT
672  * ELM_FLIP_CUBE_RIGHT
673  * 
674  * FIXME: add - ELM_FLIP_CUBE_UP
675  * FIXMEL add - ELM_FLIP_CUBE_DOWN
676  *
677  * @ingroup Flip
678  */
679 EAPI void
680 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
681 {
682    ELM_CHECK_WIDTYPE(obj, widtype);
683    Widget_Data *wd = elm_widget_data_get(obj);
684    if (!wd) return;
685    if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
686    flip_show_hide(obj);
687    wd->mode = mode;
688    wd->start = ecore_loop_time_get();
689    wd->len = 0.5;
690    // force calc to contents are the right size before transition
691    evas_smart_objects_calculate(evas_object_evas_get(obj));
692    _flip(obj);
693    // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
694    evas_object_map_enable_set(wd->front.content, 0);
695    evas_object_map_enable_set(wd->back.content, 0);
696    evas_object_resize(wd->front.content, 0, 0);
697    evas_object_resize(wd->back.content, 0, 0);
698    evas_smart_objects_calculate(evas_object_evas_get(obj));
699    _configure(obj);
700    // FIXME: end hack
701 }