Merge branch 'master' into svn_merge
[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  *
7  * This holds 2 content objects: one on the front and one on the back. It
8  * allows you to flip from front to back and vice-versa using various effects.
9  *
10  * Supported flip types:
11  * ELM_FLIP_ROTATE_Y_CENTER_AXIS
12  * ELM_FLIP_ROTATE_X_CENTER_AXIS
13  * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
14  * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
15  * ELM_FLIP_CUBE_LEFT
16  * ELM_FLIP_CUBE_RIGHT
17  * ELM_FLIP_CUBE_UP
18  * ELM_FLIP_CUBE_DOWN
19  * ELM_FLIP_PAGE_LEFT
20  * ELM_FLIP_PAGE_RIGHT
21  * ELM_FLIP_PAGE_UP
22  * ELM_FLIP_PAGE_DOWN
23  *
24  * Signals that you can add callbacks for are:
25  *
26  * "animate,done" - when a flip animation is finished
27  */
28
29 typedef struct _Widget_Data Widget_Data;
30 typedef struct _Slice Slice;
31 typedef struct _Vertex2 Vertex2;
32 typedef struct _Vertex3 Vertex3;
33
34 struct _Slice
35 {
36    Evas_Object *obj;
37    double u[4], v[4], x[4], y[4], z[4];
38 };
39
40 struct _Vertex2
41 {
42    double x, y;
43 };
44
45 struct _Vertex3
46 {
47    double x, y, z;
48 };
49
50 struct _Widget_Data
51 {
52    Evas_Object *obj;
53    Ecore_Animator *animator;
54    double start, len;
55    Elm_Flip_Mode mode;
56    Evas_Object *clip;
57    Evas_Object *event[4];
58    struct {
59       Evas_Object *content, *clip;
60    } front, back;
61    Ecore_Job *job;
62    Evas_Coord down_x, down_y, x, y, ox, oy, w, h;
63    Elm_Flip_Interaction intmode;
64    int dir;
65    double    dir_hitsize[4];
66    Eina_Bool dir_enabled[4];
67    int slices_w, slices_h;
68    Slice **slices, **slices2;
69
70    Eina_Bool state : 1;
71    Eina_Bool down : 1;
72    Eina_Bool finish : 1;
73    Eina_Bool started : 1;
74    Eina_Bool backflip : 1;
75    Eina_Bool pageflip : 1;
76 };
77
78 static const char *widtype = NULL;
79 static void _del_hook(Evas_Object *obj);
80 static void _theme_hook(Evas_Object *obj);
81 static void _sizing_eval(Evas_Object *obj);
82 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
83 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
84
85 static void _state_slices_clear(Widget_Data *st);
86 static void _configure(Evas_Object *obj);
87
88 static const char SIG_ANIMATE_BEGIN[] = "animate,begin";
89 static const char SIG_ANIMATE_DONE[] = "animate,done";
90
91 static const Evas_Smart_Cb_Description _signals[] = {
92    {SIG_ANIMATE_BEGIN, ""},
93    {SIG_ANIMATE_DONE, ""},
94    {NULL, NULL}
95 };
96
97 static void
98 _del_hook(Evas_Object *obj)
99 {
100    Widget_Data *wd = elm_widget_data_get(obj);
101    if (!wd) return;
102    if (wd->animator) ecore_animator_del(wd->animator);
103    _state_slices_clear(wd);
104    free(wd);
105 }
106
107 static void
108 _theme_hook(Evas_Object *obj)
109 {
110    Widget_Data *wd = elm_widget_data_get(obj);
111    if (!wd) return;
112    _sizing_eval(obj);
113 }
114
115 static Eina_Bool
116 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
117 {
118    Widget_Data *wd = elm_widget_data_get(obj);
119
120    if (!wd)
121      return EINA_FALSE;
122
123    /* Try Focus cycle in subitem */
124    if (wd->state)
125      return elm_widget_focus_next_get(wd->front.content, dir, next);
126    else
127      return elm_widget_focus_next_get(wd->back.content, dir, next);
128
129 }
130
131 static void
132 _sizing_eval(Evas_Object *obj)
133 {
134    Widget_Data *wd = elm_widget_data_get(obj);
135    Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
136    Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
137    int fingx = 0, fingy = 0;
138    if (!wd) return;
139    if (wd->front.content)
140      evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
141    if (wd->back.content)
142      evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
143    if (wd->front.content)
144      evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
145    if (wd->back.content)
146      evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
147
148    if (minw2 > minw) minw = minw2;
149    if (minh2 > minh) minh = minh2;
150    if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
151    if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
152
153    if (wd->dir_enabled[0]) fingy++;
154    if (wd->dir_enabled[1]) fingy++;
155    if (wd->dir_enabled[2]) fingx++;
156    if (wd->dir_enabled[3]) fingx++;
157
158    elm_coords_finger_size_adjust(fingx, &minw, fingy, &minh);
159
160    evas_object_size_hint_min_set(obj, minw, minh);
161    evas_object_size_hint_max_set(obj, maxw, maxh);
162 }
163
164 static void
165 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
166 {
167    Widget_Data *wd = elm_widget_data_get(data);
168    if (!wd) return;
169    _sizing_eval(data);
170 }
171
172 static void
173 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
174 {
175    Widget_Data *wd = elm_widget_data_get(obj);
176    Evas_Object *sub = event_info;
177    if (!wd) return;
178    if (sub == wd->front.content)
179      {
180         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
181                                             _changed_size_hints, obj);
182         wd->front.content = NULL;
183         evas_object_hide(wd->front.clip);
184         _sizing_eval(obj);
185      }
186    else if (sub == wd->back.content)
187      {
188         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
189                                             _changed_size_hints, obj);
190         wd->back.content = NULL;
191         evas_object_hide(wd->back.clip);
192         _sizing_eval(obj);
193      }
194 }
195
196 static Slice *
197 _slice_new(Widget_Data *st __UNUSED__, Evas_Object *obj)
198 {
199    Slice *sl;
200
201    sl = calloc(1, sizeof(Slice));
202    if (!sl) return NULL;
203    sl->obj = evas_object_image_add(evas_object_evas_get(obj));
204    elm_widget_sub_object_add(st->obj, sl->obj);
205    evas_object_clip_set(sl->obj, evas_object_clip_get(st->obj));
206    evas_object_smart_member_add(sl->obj, st->obj);
207    evas_object_image_smooth_scale_set(sl->obj, 0);
208    evas_object_pass_events_set(sl->obj, 1);
209    evas_object_image_source_set(sl->obj, obj);
210    return sl;
211 }
212
213 static void
214 _slice_free(Slice *sl)
215 {
216    evas_object_del(sl->obj);
217    free(sl);
218 }
219
220 static void
221 _slice_apply(Widget_Data *st, Slice *sl,
222              Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__, Evas_Coord w, Evas_Coord h __UNUSED__,
223              Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
224 {
225    Evas_Map *m;
226    int i;
227
228    m = evas_map_new(4);
229    if (!m) return;
230    evas_map_smooth_set(m, 0);
231    for (i = 0; i < 4; i++)
232      {
233         evas_map_point_color_set(m, i, 255, 255, 255, 255);
234         if (st->dir == 0)
235           {
236              int p[4] = { 0, 1, 2, 3 };
237              evas_map_point_coord_set(m, i, ox + sl->x[p[i]], oy + sl->y[p[i]], sl->z[p[i]]);
238              evas_map_point_image_uv_set(m, i, sl->u[p[i]] , sl->v[p[i]]);
239           }
240         else if (st->dir == 1)
241           {
242              int p[4] = { 1, 0, 3, 2 };
243              evas_map_point_coord_set(m, i, ox + (w - sl->x[p[i]]), oy + sl->y[p[i]], sl->z[p[i]]);
244              evas_map_point_image_uv_set(m, i, ow - sl->u[p[i]] , sl->v[p[i]]);
245           }
246         else if (st->dir == 2)
247           {
248              int p[4] = { 1, 0, 3, 2 };
249              evas_map_point_coord_set(m, i, ox + sl->y[p[i]], oy + sl->x[p[i]], sl->z[p[i]]);
250              evas_map_point_image_uv_set(m, i, sl->v[p[i]] , sl->u[p[i]]);
251           }
252         else if (st->dir == 3)
253           {
254              int p[4] = { 0, 1, 2, 3 };
255              evas_map_point_coord_set(m, i, ox + sl->y[p[i]], oy + (w - sl->x[p[i]]), sl->z[p[i]]);
256              evas_map_point_image_uv_set(m, i, sl->v[p[i]] , oh - sl->u[p[i]]);
257           }
258      }
259    evas_object_map_enable_set(sl->obj, EINA_TRUE);
260    evas_object_image_fill_set(sl->obj, 0, 0, ow, oh);
261    evas_object_map_set(sl->obj, m);
262    evas_map_free(m);
263 }
264
265 static void
266 _slice_3d(Widget_Data *st __UNUSED__, Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
267 {
268    Evas_Map *m = (Evas_Map *)evas_object_map_get(sl->obj);
269    int i;
270
271    if (!m) return;
272    // vanishing point is center of page, and focal dist is 1024
273    evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 1024);
274    for (i = 0; i < 4; i++)
275      {
276         Evas_Coord x, y, z;
277         evas_map_point_coord_get(m, i, &x, &y, &z);
278         evas_map_point_coord_set(m, i, x, y, 0);
279      }
280    if (evas_map_util_clockwise_get(m)) evas_object_show(sl->obj);
281    else evas_object_hide(sl->obj);
282    evas_object_map_set(sl->obj, m);
283 }
284
285 static void
286 _slice_light(Widget_Data *st __UNUSED__, Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
287 {
288    Evas_Map *m = (Evas_Map *)evas_object_map_get(sl->obj);
289    int i;
290
291    if (!m) return;
292    evas_map_util_3d_lighting(m,
293                              // light position
294                              // (centered over page 10 * h toward camera)
295                              x + (w / 2)  , y + (h / 2)  , -10000,
296                              255, 255, 255, // light color
297                              0 , 0 , 0); // ambient minimum
298    // multiply brightness by 1.2 to make lightish bits all white so we dont
299    // add shading where we could otherwise be pure white
300    for (i = 0; i < 4; i++)
301      {
302         int r, g, b, a;
303
304         evas_map_point_color_get(m, i, &r, &g, &b, &a);
305         r = (double)r * 1.2; if (r > 255) r = 255;
306         g = (double)g * 1.2; if (g > 255) g = 255;
307         b = (double)b * 1.2; if (b > 255) b = 255;
308         evas_map_point_color_set(m, i, r, g, b, a);
309      }
310    evas_object_map_set(sl->obj, m);
311 }
312
313 static void
314 _slice_xyz(Widget_Data *st __UNUSED__, Slice *sl,
315            double x1, double y1, double z1,
316            double x2, double y2, double z2,
317            double x3, double y3, double z3,
318            double x4, double y4, double z4)
319 {
320    sl->x[0] = x1; sl->y[0] = y1; sl->z[0] = z1;
321    sl->x[1] = x2; sl->y[1] = y2; sl->z[1] = z2;
322    sl->x[2] = x3; sl->y[2] = y3; sl->z[2] = z3;
323    sl->x[3] = x4; sl->y[3] = y4; sl->z[3] = z4;
324 }
325
326 static void
327 _slice_uv(Widget_Data *st __UNUSED__, Slice *sl,
328           double u1, double v1,
329           double u2, double v2,
330           double u3, double v3,
331           double u4, double v4)
332 {
333    sl->u[0] = u1; sl->v[0] = v1;
334    sl->u[1] = u2; sl->v[1] = v2;
335    sl->u[2] = u3; sl->v[2] = v3;
336    sl->u[3] = u4; sl->v[3] = v4;
337 }
338
339 static void
340 _deform_point(Vertex2 *vi, Vertex3 *vo, double rho, double theta, double A)
341 {
342    // ^Y
343    // |
344    // |    X
345    // +---->
346    // theta == cone angle (0 -> PI/2)
347    // A     == distance of cone apex from origin
348    // rho   == angle of cone from vertical axis (...-PI/2 to PI/2...)
349    Vertex3  v1;
350    double d, r, b;
351
352    d = sqrt((vi->x * vi->x) + pow(vi->y - A, 2));
353    r = d * sin(theta);
354    b = asin(vi->x / d) / sin(theta);
355
356    v1.x = r * sin(b);
357    v1.y = d + A - (r * (1 - cos(b)) * sin(theta));
358    v1.z = r * (1 - cos(b)) * cos(theta);
359
360    vo->x = (v1.x * cos(rho)) - (v1.z * sin(rho));
361    vo->y = v1.y;
362    vo->z = (v1.x * sin(rho)) + (v1.z * cos(rho));
363 }
364
365 static void
366 _interp_point(Vertex3 *vi1, Vertex3 *vi2, Vertex3 *vo, double v)
367 {
368    vo->x = (v * vi2->x) + ((1.0 - v) * vi1->x);
369    vo->y = (v * vi2->y) + ((1.0 - v) * vi1->y);
370    vo->z = (v * vi2->z) + ((1.0 - v) * vi1->z);
371 }
372
373 static void
374 _state_slices_clear(Widget_Data *st)
375 {
376    int i, j, num;
377
378    if (st->slices)
379      {
380         num = 0;
381         for (j = 0; j < st->slices_h; j++)
382           {
383              for (i = 0; i < st->slices_w; i++)
384                {
385                   if (st->slices[num]) _slice_free(st->slices[num]);
386                   if (st->slices2[num]) _slice_free(st->slices2[num]);
387                   num++;
388                }
389           }
390         free(st->slices);
391         free(st->slices2);
392         st->slices = NULL;
393         st->slices2 = NULL;
394      }
395    st->slices_w = 0;
396    st->slices_h = 0;
397 }
398
399 static int
400 _slice_obj_color_sum(Slice *s, int p, int *r, int *g, int *b, int *a)
401 {
402    Evas_Map *m;
403    int rr = 0, gg = 0, bb = 0, aa = 0;
404
405    if (!s) return 0;
406    m = (Evas_Map *)evas_object_map_get(s->obj);
407    if (!m) return 0;
408    evas_map_point_color_get(m, p, &rr, &gg, &bb, &aa);
409    *r += rr; *g += gg; *b += bb; *a += aa;
410    return 1;
411 }
412
413 static void
414 _slice_obj_color_set(Slice *s, int p, int r, int g, int b, int a)
415 {
416    Evas_Map *m;
417
418    if (!s) return;
419    m = (Evas_Map *)evas_object_map_get(s->obj);
420    if (!m) return;
421    evas_map_point_color_set(m, p, r, g, b, a);
422    evas_object_map_set(s->obj, m);
423 }
424
425 static void
426 _slice_obj_vert_color_merge(Slice *s1, int p1, Slice *s2, int p2,
427                             Slice *s3, int p3, Slice *s4, int p4)
428 {
429    int r = 0, g = 0, b = 0, a = 0, n = 0;
430
431    n += _slice_obj_color_sum(s1, p1, &r, &g, &b, &a);
432    n += _slice_obj_color_sum(s2, p2, &r, &g, &b, &a);
433    n += _slice_obj_color_sum(s3, p3, &r, &g, &b, &a);
434    n += _slice_obj_color_sum(s4, p4, &r, &g, &b, &a);
435
436    if (n < 1) return;
437    r /= n; g /= n; b /= n; a /= n;
438
439    _slice_obj_color_set(s1, p1, r, g, b, a);
440    _slice_obj_color_set(s2, p2, r, g, b, a);
441    _slice_obj_color_set(s3, p3, r, g, b, a);
442    _slice_obj_color_set(s4, p4, r, g, b, a);
443 }
444
445 static int
446 _state_update(Widget_Data *st)
447 {
448    Evas_Coord x1, y1, x2, y2, mx, my;
449    Evas_Coord x, y, w, h, ox, oy, ow, oh;
450    int i, j, num, nn, jump, num2;
451    Slice *sl;
452    double b, minv = 0.0, minva, mgrad;
453    int gx, gy, gszw, gszh, gw, gh, col, row, nw, nh;
454    double rho, A, theta, perc, percm, n, rhol, Al, thetal;
455    Vertex2 *tvi;
456    Vertex3 *tvo, *tvol;
457    Evas_Object *front, *back;
458
459    st->backflip = 1;
460    if (st->state)
461      {
462         front = st->front.content;
463         back = st->front.content;
464      }
465    else
466      {
467         front = st->back.content;
468         back = st->back.content;
469      }
470
471    evas_object_geometry_get(st->obj, &x, &y, &w, &h);
472    ox = x; oy = y; ow = w; oh = h;
473    x1 = st->down_x;
474    y1 = st->down_y;
475    x2 = st->x;
476    y2 = st->y;
477
478    if (st->dir == 0)
479      {
480         // no nothing. left drag is standard
481      }
482    else if (st->dir == 1)
483      {
484         x1 = (w - 1) - x1;
485         x2 = (w - 1) - x2;
486      }
487    else if (st->dir == 2)
488      {
489         Evas_Coord tmp;
490
491         tmp = x1; x1 = y1; y1 = tmp;
492         tmp = x2; x2 = y2; y2 = tmp;
493         tmp = w; w = h; h = tmp;
494      }
495    else if (st->dir == 3)
496      {
497         Evas_Coord tmp;
498
499         tmp = x1; x1 = y1; y1 = tmp;
500         tmp = x2; x2 = y2; y2 = tmp;
501         tmp = w; w = h; h = tmp;
502         x1 = (w - 1) - x1;
503         x2 = (w - 1) - x2;
504      }
505
506    if (x2 >= x1) x2 = x1 - 1;
507    mx = (x1 + x2) / 2;
508    my = (y1 + y2) / 2;
509
510    if (mx < 0) mx = 0;
511    else if (mx >= w) mx = w - 1;
512    if (my < 0) my = 0;
513    else if (my >= h) my = h - 1;
514
515    mgrad = (double)(y1 - y2) / (double)(x1 - x2);
516
517    if (mx < 1) mx = 1; // quick hack to keep curl line visible
518
519    if (mgrad == 0.0) // special horizontal case
520       mgrad = 0.001; // quick dirty hack for now
521    // else
522      {
523         minv = 1.0 / mgrad;
524         // y = (m * x) + b
525         b = my + (minv * mx);
526      }
527    if ((b >= -5) && (b <= (h + 5)))
528      {
529         if (minv > 0.0) // clamp to h
530           {
531              minv = (double)(h + 5 - my) / (double)(mx);
532              b = my + (minv * mx);
533           }
534         else // clamp to 0
535           {
536              minv = (double)(-5 - my) / (double)(mx);
537              b = my + (minv * mx);
538           }
539      }
540
541    perc = (double)x2 / (double)x1;
542    percm = (double)mx / (double)x1;
543    if (perc < 0.0) perc = 0.0;
544    else if (perc > 1.0) perc = 1.0;
545    if (percm < 0.0) percm = 0.0;
546    else if (percm > 1.0) percm = 1.0;
547
548    minva = atan(minv) / (M_PI / 2);
549    if (minva < 0.0) minva = -minva;
550
551    // A = apex of cone
552    if (b <= 0) A = b;
553    else A = h - b;
554    if (A < -(h * 20)) A = -h * 20;
555    //--//
556    Al = -5;
557
558    // rho = is how much the page is turned
559    n = 1.0 - perc;
560    n = 1.0 - cos(n * M_PI / 2.0);
561    n = n * n;
562    rho = -(n * M_PI);
563    //--//
564    rhol = -(n * M_PI);
565
566    // theta == curliness (how much page culrs in on itself
567    n = sin((1.0 - perc) * M_PI);
568    n = n * 1.2;
569    theta = 7.86 + n;
570    //--//
571    n = sin((1.0 - perc) * M_PI);
572    n = 1.0 - n;
573    n = n * n;
574    n = 1.0 - n;
575    thetal = 7.86 + n;
576
577    nw = 16;
578    nh = 16;
579    if (nw < 1) nw = 1;
580    if (nh < 1) nh = 1;
581    gszw = w / nw;
582    gszh = h / nh;
583    if (gszw < 4) gszw = 4;
584    if (gszh < 4) gszh = 4;
585
586    nw = (w + gszw - 1) / gszw;
587    nh = (h + gszh - 1) / gszh;
588    if ((st->slices_w != nw) || (st->slices_h != nh)) _state_slices_clear(st);
589    st->slices_w = nw;
590    st->slices_h = nh;
591    if (!st->slices)
592      {
593         st->slices = calloc(st->slices_w * st->slices_h, sizeof(Slice *));
594         if (!st->slices) return 0;
595         st->slices2 = calloc(st->slices_w * st->slices_h, sizeof(Slice *));
596         if (!st->slices2)
597           {
598              free(st->slices);
599              st->slices = NULL;
600              return 0;
601           }
602      }
603
604    num = (st->slices_w + 1) * (st->slices_h + 1);
605
606    tvi = alloca(sizeof(Vertex2) * num);
607    tvo = alloca(sizeof(Vertex3) * num);
608    tvol = alloca(sizeof(Vertex3) * (st->slices_w + 1));
609
610    for (col = 0, gx = 0; gx <= (w + gszw - 1); gx += gszw, col++)
611      {
612         Vertex2 vil;
613
614         vil.x = gx;
615         vil.y = h - ((gx * h) / (w + gszw - 1));
616         _deform_point(&vil, &(tvol[col]), rhol, thetal, Al);
617      }
618
619    n = minva * sin(perc * M_PI);
620    n = n * n;
621
622    num = 0;
623    for (col = 0, gx = 0; gx <= (w + gszw - 1); gx += gszw, col++)
624      {
625         for (gy = 0; gy <= (h + gszh - 1); gy += gszh)
626           {
627              Vertex2 vi;
628              Vertex3 vo, tvo1;
629
630              if (gx > w) vi.x = w;
631              else vi.x = gx;
632              if (gy > h) vi.y = h;
633              else vi.y = gy;
634              _deform_point(&vi, &vo, rho, theta, A);
635              tvo1 = tvol[col];
636              if (gy > h) tvo1.y = h;
637              else tvo1.y = gy;
638              _interp_point(&vo, &tvo1, &(tvo[num]), n);
639              num++;
640           }
641      }
642
643    jump = st->slices_h + 1;
644    for (col = 0, gx = 0; gx < w; gx += gszw, col++)
645      {
646         num = st->slices_h * col;
647         num2 = jump * col;
648
649         gw = gszw;
650         if ((gx + gw) > w) gw = w - gx;
651
652         for (row = 0, gy = 0; gy < h; gy += gszh, row++)
653           {
654              Vertex3 vo[4];
655
656              if (b > 0) nn = num + st->slices_h - row - 1;
657              else nn = num + row;
658
659              gh = gszh;
660              if ((gy + gh) > h) gh = h - gy;
661
662              vo[0] = tvo[num2 + row];
663              vo[1] = tvo[num2 + row + jump];
664              vo[2] = tvo[num2 + row + jump + 1];
665              vo[3] = tvo[num2 + row + 1];
666 #define SWP(a, b) do {typeof(a) vt; vt = (a); (a) = (b); (b) = vt;} while (0)
667              if (b > 0)
668                {
669                   SWP(vo[0], vo[3]);
670                   SWP(vo[1], vo[2]);
671                   vo[0].y = h - vo[0].y;
672                   vo[1].y = h - vo[1].y;
673                   vo[2].y = h - vo[2].y;
674                   vo[3].y = h - vo[3].y;
675                }
676
677              // FRONT
678              sl = st->slices[nn];
679              if (!sl)
680                {
681                   sl = _slice_new(st, front);
682                   st->slices[nn] = sl;
683                }
684              _slice_xyz(st, sl,
685                         vo[0].x, vo[0].y, vo[0].z,
686                         vo[1].x, vo[1].y, vo[1].z,
687                         vo[2].x, vo[2].y, vo[2].z,
688                         vo[3].x, vo[3].y, vo[3].z);
689              if (b <= 0)
690                 _slice_uv(st, sl,
691                           gx,       gy,       gx + gw,  gy,
692                           gx + gw,  gy + gh,  gx,       gy + gh);
693              else
694                 _slice_uv(st, sl,
695                           gx,       h - (gy + gh), gx + gw,  h - (gy + gh),
696                           gx + gw,  h - gy,        gx,       h - gy);
697
698                           // BACK
699              sl = st->slices2[nn];
700              if (!sl)
701                {
702                   sl = _slice_new(st, back);
703                   st->slices2[nn] = sl;
704                }
705
706              _slice_xyz(st, sl,
707                         vo[1].x, vo[1].y, vo[1].z,
708                         vo[0].x, vo[0].y, vo[0].z,
709                         vo[3].x, vo[3].y, vo[3].z,
710                         vo[2].x, vo[2].y, vo[2].z);
711              if (st->backflip)
712                {
713                   if (b <= 0)
714                      _slice_uv(st, sl,
715                                gx + gw, gy,       gx,       gy,
716                                gx,      gy + gh,  gx + gw,  gy + gh);
717                   else
718                      _slice_uv(st, sl,
719                                gx + gw, h - (gy + gh), gx,      h - (gy + gh),
720                                gx,      h - gy,        gx + gw, h - gy);
721                }
722              else
723                {
724                   if (b <= 0)
725                      _slice_uv(st, sl,
726                                w - (gx + gw), gy,       w - (gx),      gy,
727                                w - (gx),      gy + gh,  w - (gx + gw), gy + gh);
728                   else
729                      _slice_uv(st, sl,
730                                w - (gx + gw), h - (gy + gh), w - (gx),      h - (gy + gh),
731                                w - (gx),      h - gy,        w - (gx + gw), h - gy);
732                }
733           }
734      }
735
736    num = 0;
737    for (j = 0; j < st->slices_h; j++)
738      {
739         for (i = 0; i < st->slices_w; i++)
740           {
741              _slice_apply(st, st->slices[num], x, y, w, h, ox, oy, ow, oh);
742              _slice_apply(st, st->slices2[num], x, y, w, h, ox, oy, ow, oh);
743              _slice_light(st, st->slices[num], ox, oy, ow, oh);
744              _slice_light(st, st->slices2[num], ox, oy, ow, oh);
745              num++;
746           }
747      }
748
749    for (i = 0; i <= st->slices_w; i++)
750      {
751         num = i * st->slices_h;
752         for (j = 0; j <= st->slices_h; j++)
753           {
754              Slice *s[4];
755
756              s[0] = s[1] = s[2] = s[3] = NULL;
757              if ((i > 0)            && (j > 0))
758                 s[0] = st->slices[num - 1 - st->slices_h];
759              if ((i < st->slices_w) && (j > 0))
760                 s[1] = st->slices[num - 1];
761              if ((i > 0)            && (j < st->slices_h))
762                 s[2] = st->slices[num - st->slices_h];
763              if ((i < st->slices_w) && (j < st->slices_h))
764                 s[3] = st->slices[num];
765              if (st->dir == 0)
766                 _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
767                                             s[2], 1, s[3], 0);
768              else if (st->dir == 1)
769                 _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
770                                             s[2], 0, s[3], 1);
771              else if (st->dir == 2)
772                 _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
773                                             s[2], 0, s[3], 1);
774              else if (st->dir == 3)
775                 _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
776                                             s[2], 1, s[3], 0);
777              s[0] = s[1] = s[2] = s[3] = NULL;
778              if ((i > 0)            && (j > 0))
779                 s[0] = st->slices2[num - 1 - st->slices_h];
780              if ((i < st->slices_w) && (j > 0))
781                 s[1] = st->slices2[num - 1];
782              if ((i > 0)            && (j < st->slices_h))
783                 s[2] = st->slices2[num - st->slices_h];
784              if ((i < st->slices_w) && (j < st->slices_h))
785                 s[3] = st->slices2[num];
786              if (st->dir == 0)
787                 _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
788                                             s[2], 0, s[3], 1);
789              else if (st->dir == 1)
790                 _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
791                                             s[2], 1, s[3], 0);
792              else if (st->dir == 2)
793                 _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
794                                             s[2], 1, s[3], 0);
795              else if (st->dir == 3)
796                 _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
797                                             s[2], 0, s[3], 1);
798              num++;
799           }
800      }
801
802    num = 0;
803    for (i = 0; i < st->slices_w; i++)
804      {
805         for (j = 0; j < st->slices_h; j++)
806           {
807              _slice_3d(st, st->slices[num], ox, oy, ow, oh);
808              _slice_3d(st, st->slices2[num], ox, oy, ow, oh);
809              num++;
810           }
811      }
812
813    return 1;
814 }
815
816 static void
817 _state_end(Widget_Data *st)
818 {
819    _state_slices_clear(st);
820 }
821
822
823 static void
824 flip_show_hide(Evas_Object *obj)
825 {
826    Widget_Data *wd = elm_widget_data_get(obj);
827    if (elm_flip_front_get(obj))
828      {
829         if (wd->pageflip)
830           {
831              if (wd->front.content)
832                {
833                   evas_object_move(wd->front.content, 4999, 4999);
834                   evas_object_show(wd->front.clip);
835                }
836              else
837                 evas_object_hide(wd->front.clip);
838              if (wd->back.content)
839                 evas_object_show(wd->back.clip);
840              else
841                 evas_object_hide(wd->back.clip);
842           }
843         else
844           {
845              if (wd->front.content)
846                 evas_object_show(wd->front.clip);
847              else
848                 evas_object_hide(wd->front.clip);
849              if (wd->back.content)
850                 evas_object_hide(wd->back.clip);
851              else
852                 evas_object_hide(wd->back.clip);
853           }
854      }
855    else
856      {
857         if (wd->pageflip)
858           {
859              if (wd->front.content)
860                 evas_object_show(wd->front.clip);
861              else
862                 evas_object_hide(wd->front.clip);
863              if (wd->back.content)
864                {
865                   evas_object_move(wd->back.content, 4999, 4999);
866                   evas_object_show(wd->back.clip);
867                }
868              else
869                 evas_object_hide(wd->back.clip);
870           }
871         else
872           {
873              if (wd->front.content)
874                 evas_object_hide(wd->front.clip);
875              else
876                 evas_object_hide(wd->front.clip);
877              if (wd->back.content)
878                 evas_object_show(wd->back.clip);
879              else
880                 evas_object_hide(wd->back.clip);
881           }
882      }
883 }
884
885 static void
886 _flip_do(Evas_Object *obj, double t, Elm_Flip_Mode mode, int lin, int rev)
887 {
888    Evas_Coord x, y, w, h;
889    double p, deg, pp;
890    Evas_Map *mf, *mb;
891    Evas_Coord cx, cy, px, py, foc;
892    int lx, ly, lz, lr, lg, lb, lar, lag, lab;
893    Widget_Data *wd = elm_widget_data_get(obj);
894
895    if (!wd) return;
896
897    mf = evas_map_new(4);
898    evas_map_smooth_set(mf, 0);
899    mb = evas_map_new(4);
900    evas_map_smooth_set(mb, 0);
901
902    if (wd->front.content)
903      {
904         const char *type = evas_object_type_get(wd->front.content);
905
906         // FIXME: only handles filled obj
907         if ((type) && (!strcmp(type, "image")))
908           {
909              int iw, ih;
910              evas_object_image_size_get(wd->front.content, &iw, &ih);
911              evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
912              evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
913              evas_map_point_image_uv_set(mf, 0, 0, 0);
914              evas_map_point_image_uv_set(mf, 1, iw, 0);
915              evas_map_point_image_uv_set(mf, 2, iw, ih);
916              evas_map_point_image_uv_set(mf, 3, 0, ih);
917           }
918         else
919           {
920              evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
921              evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
922           }
923      }
924    if (wd->back.content)
925      {
926         const char *type = evas_object_type_get(wd->back.content);
927
928         if ((type) && (!strcmp(type, "image")))
929           {
930              int iw, ih;
931              evas_object_image_size_get(wd->back.content, &iw, &ih);
932              evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
933              evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
934              evas_map_point_image_uv_set(mb, 0, 0, 0);
935              evas_map_point_image_uv_set(mb, 1, iw, 0);
936              evas_map_point_image_uv_set(mb, 2, iw, ih);
937              evas_map_point_image_uv_set(mb, 3, 0, ih);
938           }
939         else
940           {
941              evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
942              evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
943           }
944      }
945
946    evas_object_geometry_get(obj, &x, &y, &w, &h);
947
948    cx = x + (w / 2);
949    cy = y + (h / 2);
950
951    px = x + (w / 2);
952    py = y + (h / 2);
953    foc = 2048;
954
955    lx = cx;
956    ly = cy;
957    lz = -10000;
958    lr = 255;
959    lg = 255;
960    lb = 255;
961    lar = 0;
962    lag = 0;
963    lab = 0;
964
965    switch (mode)
966      {
967       case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
968          p = 1.0 - t;
969          pp = p;
970          if (!lin) pp = (p * p);
971          p = 1.0 - pp;
972          if (wd->state) deg = 180.0 * p;
973          else deg = 180 + (180.0 * p);
974          if (rev) deg = -deg;
975          evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
976          evas_map_util_3d_rotate(mb, 0.0, 180 + deg, 0.0, cx, cy, 0);
977          break;
978       case ELM_FLIP_ROTATE_X_CENTER_AXIS:
979          p = 1.0 - t;
980          pp = p;
981          if (!lin) pp = (p * p);
982          p = 1.0 - pp;
983          if (wd->state) deg = 180.0 * p;
984          else deg = 180 + (180.0 * p);
985          if (rev) deg = -deg;
986          evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
987          evas_map_util_3d_rotate(mb, 180.0 + deg, 0.0, 0.0, cx, cy, 0);
988          break;
989       case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
990          p = 1.0 - t;
991          pp = p;
992          if (!lin) pp = (p * p);
993          p = 1.0 - pp;
994          if (wd->state) deg = 180.0 * p;
995          else deg = 180 + (180.0 * p);
996          if (rev) deg = -deg;
997          evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
998          evas_map_util_3d_rotate(mb, 180 + deg, 0.0, 180 + deg, cx, cy, 0);
999          break;
1000       case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
1001          p = 1.0 - t;
1002          pp = p;
1003          if (!lin) pp = (p * p);
1004          p = 1.0 - pp;
1005          if (wd->state) deg = 180.0 * p;
1006          else deg = 180 + (180.0 * p);
1007          if (rev) deg = -deg;
1008          evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
1009          evas_map_util_3d_rotate(mb, 0.0, 180.0 + deg, 180.0 + deg, cx, cy, 0);
1010          break;
1011       case ELM_FLIP_CUBE_LEFT:
1012          p = 1.0 - t;
1013          pp = p;
1014          if (!lin) pp = (p * p);
1015          p = 1.0 - pp;
1016          deg = -90.0 * p;
1017          if (wd->state)
1018            {
1019               evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
1020               evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
1021            }
1022          else
1023            {
1024               evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
1025               evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
1026            }
1027          break;
1028       case ELM_FLIP_CUBE_RIGHT:
1029          p = 1.0 - t;
1030          pp = p;
1031          if (!lin) pp = (p * p);
1032          p = 1.0 - pp;
1033          deg = 90.0 * p;
1034          if (wd->state)
1035            {
1036               evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
1037               evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
1038            }
1039          else
1040            {
1041               evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
1042               evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
1043            }
1044          break;
1045       case ELM_FLIP_CUBE_UP:
1046          p = 1.0 - t;
1047          if (!lin) pp = (p * p);
1048          p = 1.0 - pp;
1049          deg = -90.0 * p;
1050          if (wd->state)
1051            {
1052               evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
1053               evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
1054            }
1055          else
1056            {
1057               evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
1058               evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
1059            }
1060          break;
1061       case ELM_FLIP_CUBE_DOWN:
1062          p = 1.0 - t;
1063          pp = p;
1064          if (!lin) pp = (p * p);
1065          p = 1.0 - pp;
1066          deg = 90.0 * p;
1067          if (wd->state)
1068            {
1069               evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
1070               evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
1071            }
1072          else
1073            {
1074               evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
1075               evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
1076            }
1077          break;
1078       case ELM_FLIP_PAGE_LEFT:
1079         break;
1080       case ELM_FLIP_PAGE_RIGHT:
1081         break;
1082       case ELM_FLIP_PAGE_UP:
1083         break;
1084       case ELM_FLIP_PAGE_DOWN:
1085         break;
1086       default:
1087          break;
1088      }
1089
1090
1091    if (wd->front.content)
1092      {
1093         evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
1094         evas_map_util_3d_perspective(mf, px, py, 0, foc);
1095         evas_object_map_set(wd->front.content, mf);
1096         evas_object_map_enable_set(wd->front.content, 1);
1097         if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
1098         else evas_object_hide(wd->front.clip);
1099      }
1100
1101    if (wd->back.content)
1102      {
1103         evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
1104         evas_map_util_3d_perspective(mb, px, py, 0, foc);
1105         evas_object_map_set(wd->back.content, mb);
1106         evas_object_map_enable_set(wd->back.content, 1);
1107         if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
1108         else evas_object_hide(wd->back.clip);
1109      }
1110
1111    evas_map_free(mf);
1112    evas_map_free(mb);
1113 }
1114
1115 static void
1116 _showhide(Evas_Object *obj)
1117 {
1118    Widget_Data *wd = elm_widget_data_get(obj);
1119    Evas_Coord x, y, w, h;
1120    if (!wd) return;
1121
1122    evas_object_geometry_get(obj, &x, &y, &w, &h);
1123    if (wd->front.content)
1124      {
1125         if ((wd->pageflip) && (wd->state))
1126           {
1127              evas_object_move(wd->front.content, 4999, 4999);
1128           }
1129         else
1130           {
1131              if (!wd->animator)
1132                 evas_object_move(wd->front.content, x, y);
1133           }
1134         evas_object_resize(wd->front.content, w, h);
1135      }
1136    if (wd->back.content)
1137      {
1138         if ((wd->pageflip) && (!wd->state))
1139           {
1140              evas_object_move(wd->back.content, 4999, 4999);
1141           }
1142         else
1143           {
1144              if (!wd->animator)
1145                 evas_object_move(wd->back.content, x, y);
1146           }
1147         evas_object_resize(wd->back.content, w, h);
1148      }
1149
1150 }
1151
1152 static Eina_Bool
1153 _flip(Evas_Object *obj)
1154 {
1155    Widget_Data *wd = elm_widget_data_get(obj);
1156    double t = ecore_loop_time_get() - wd->start;
1157    Evas_Coord w, h;
1158
1159    if (!wd) return ECORE_CALLBACK_CANCEL;
1160    if (!wd->animator) return ECORE_CALLBACK_CANCEL;
1161
1162    t = t / wd->len;
1163    if (t > 1.0) t = 1.0;
1164
1165    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1166    if (wd->mode == ELM_FLIP_PAGE_LEFT)
1167      {
1168         wd->dir = 0;
1169         wd->started = EINA_TRUE;
1170         wd->pageflip = EINA_TRUE;
1171         wd->down_x = w - 1;
1172         wd->down_y = h / 2;
1173         wd->x = (1.0 - t) * wd->down_x;
1174         wd->y = wd->down_y;
1175         flip_show_hide(obj);
1176         _state_update(wd);
1177      }
1178    else if (wd->mode == ELM_FLIP_PAGE_RIGHT)
1179      {
1180         wd->dir = 1;
1181         wd->started = EINA_TRUE;
1182         wd->pageflip = EINA_TRUE;
1183         wd->down_x = 0;
1184         wd->down_y = h / 2;
1185         wd->x = (t) * w;
1186         wd->y = wd->down_y;
1187         flip_show_hide(obj);
1188         _state_update(wd);
1189      }
1190    else if (wd->mode == ELM_FLIP_PAGE_UP)
1191      {
1192         wd->dir = 2;
1193         wd->started = EINA_TRUE;
1194         wd->pageflip = EINA_TRUE;
1195         wd->down_x = w / 2;
1196         wd->down_y = h - 1;
1197         wd->x = wd->down_x;
1198         wd->y = (1.0 - t) * wd->down_y;
1199         flip_show_hide(obj);
1200         _state_update(wd);
1201      }
1202    else if (wd->mode == ELM_FLIP_PAGE_DOWN)
1203      {
1204         wd->dir = 3;
1205         wd->started = EINA_TRUE;
1206         wd->pageflip = EINA_TRUE;
1207         wd->down_x = w / 2;
1208         wd->down_y = 0;
1209         wd->x = wd->down_x;
1210         wd->y = (t) * h;
1211         flip_show_hide(obj);
1212         _state_update(wd);
1213      }
1214    else
1215       _flip_do(obj, t, wd->mode, 0, 0);
1216
1217    if (t >= 1.0)
1218      {
1219         wd->pageflip = EINA_FALSE;
1220         _state_end(wd);
1221         evas_object_map_enable_set(wd->front.content, 0);
1222         evas_object_map_enable_set(wd->back.content, 0);
1223         // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
1224         evas_object_resize(wd->front.content, 0, 0);
1225         evas_object_resize(wd->back.content, 0, 0);
1226         evas_smart_objects_calculate(evas_object_evas_get(obj));
1227         // FIXME: end hack
1228         wd->animator = NULL;
1229         wd->state = !wd->state;
1230         _configure(obj);
1231         flip_show_hide(obj);
1232         evas_object_smart_callback_call(obj, SIG_ANIMATE_DONE, NULL);
1233         return ECORE_CALLBACK_CANCEL;
1234      }
1235    return ECORE_CALLBACK_RENEW;
1236 }
1237
1238 static void
1239 _configure(Evas_Object *obj)
1240 {
1241    Widget_Data *wd = elm_widget_data_get(obj);
1242    Evas_Coord x, y, w, h;
1243    Evas_Coord fsize;
1244    if (!wd) return;
1245
1246    _showhide(obj);
1247    evas_object_geometry_get(obj, &x, &y, &w, &h);
1248    // FIXME: manual flip wont get fixed
1249    if (wd->animator) _flip(obj);
1250
1251    if (wd->event[0])
1252      {
1253         fsize = (double)w * wd->dir_hitsize[0];
1254         elm_coords_finger_size_adjust(0, NULL, 1, &fsize);
1255         evas_object_move(wd->event[0], x, y);
1256         evas_object_resize(wd->event[0], w, fsize);
1257      }
1258    if (wd->event[1])
1259      {
1260         fsize = (double)w * wd->dir_hitsize[1];
1261         elm_coords_finger_size_adjust(0, NULL, 1, &fsize);
1262         evas_object_move(wd->event[1], x, y + h - fsize);
1263         evas_object_resize(wd->event[1], w, fsize);
1264      }
1265    if (wd->event[2])
1266      {
1267         fsize = (double)h * wd->dir_hitsize[2];
1268         elm_coords_finger_size_adjust(1, &fsize, 0, NULL);
1269         evas_object_move(wd->event[2], x, y);
1270         evas_object_resize(wd->event[2], fsize, h);
1271      }
1272    if (wd->event[3])
1273      {
1274         fsize = (double)h * wd->dir_hitsize[3];
1275         elm_coords_finger_size_adjust(1, &fsize, 0, NULL);
1276         evas_object_move(wd->event[3], x + w - fsize, y);
1277         evas_object_resize(wd->event[3], fsize, h);
1278      }
1279 }
1280
1281 static void
1282 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1283 {
1284    _configure(obj);
1285 }
1286
1287 static void
1288 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1289 {
1290    _configure(obj);
1291 }
1292
1293 static Eina_Bool
1294 _animate(void *data)
1295 {
1296    return _flip(data);
1297 }
1298
1299 static double
1300 _pos_get(Widget_Data *wd, int *rev, Elm_Flip_Mode *m)
1301 {
1302    Evas_Coord x, y, w, h;
1303    double t = 1.0;
1304
1305    evas_object_geometry_get(wd->obj, &x, &y, &w, &h);
1306    switch (wd->intmode)
1307      {
1308       case ELM_FLIP_INTERACTION_ROTATE:
1309       case ELM_FLIP_INTERACTION_CUBE:
1310           {
1311              if (wd->dir == 0)
1312                {
1313                   if (wd->down_x > 0)
1314                      t = 1.0 - ((double)wd->x / (double)wd->down_x);
1315                   *rev = 1;
1316                }
1317              else if (wd->dir == 1)
1318                {
1319                   if (wd->down_x < w)
1320                      t = 1.0 - ((double)(w - wd->x) / (double)(w - wd->down_x));
1321                }
1322              else if (wd->dir == 2)
1323                {
1324                   if (wd->down_y > 0)
1325                      t = 1.0 - ((double)wd->y / (double)wd->down_y);
1326                }
1327              else if (wd->dir == 3)
1328                {
1329                   if (wd->down_y < h)
1330                      t = 1.0 - ((double)(h - wd->y) / (double)(h - wd->down_y));
1331                   *rev = 1;
1332                }
1333
1334              if (t < 0.0) t = 0.0;
1335              else if (t > 1.0) t = 1.0;
1336
1337              if ((wd->dir == 0) || (wd->dir == 1))
1338                {
1339                   if (wd->intmode == ELM_FLIP_INTERACTION_ROTATE)
1340                      *m = ELM_FLIP_ROTATE_Y_CENTER_AXIS;
1341                   else if (wd->intmode == ELM_FLIP_INTERACTION_CUBE)
1342                     {
1343                        if (*rev)
1344                           *m = ELM_FLIP_CUBE_LEFT;
1345                        else
1346                           *m = ELM_FLIP_CUBE_RIGHT;
1347                     }
1348                }
1349              else
1350                {
1351                   if (wd->intmode == ELM_FLIP_INTERACTION_ROTATE)
1352                      *m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
1353                   else if (wd->intmode == ELM_FLIP_INTERACTION_CUBE)
1354                     {
1355                        if (*rev)
1356                           *m = ELM_FLIP_CUBE_UP;
1357                        else
1358                           *m = ELM_FLIP_CUBE_DOWN;
1359                     }
1360                }
1361           }
1362       default:
1363         break;
1364      }
1365    return t;
1366 }
1367
1368 static Eina_Bool
1369 _event_anim(void *data, double pos)
1370 {
1371    Widget_Data *wd = data;
1372    double p;
1373
1374    p = ecore_animator_pos_map(pos, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
1375    if (wd->finish)
1376      {
1377         if (wd->dir == 0)
1378            wd->x = wd->ox * (1.0 - p);
1379         else if (wd->dir == 1)
1380            wd->x = wd->ox + ((wd->w - wd->ox) * p);
1381         else if (wd->dir == 2)
1382            wd->y = wd->oy * (1.0 - p);
1383         else if (wd->dir == 3)
1384            wd->y = wd->oy + ((wd->h - wd->oy) * p);
1385      }
1386    else
1387      {
1388         if (wd->dir == 0)
1389            wd->x = wd->ox + ((wd->w - wd->ox) * p);
1390         else if (wd->dir == 1)
1391            wd->x = wd->ox * (1.0 - p);
1392         else if (wd->dir == 2)
1393            wd->y = wd->oy + ((wd->h - wd->oy) * p);
1394         else if (wd->dir == 3)
1395            wd->y = wd->oy * (1.0 - p);
1396      }
1397    switch (wd->intmode)
1398      {
1399       case ELM_FLIP_INTERACTION_NONE:
1400         break;
1401       case ELM_FLIP_INTERACTION_ROTATE:
1402       case ELM_FLIP_INTERACTION_CUBE:
1403           {
1404              Elm_Flip_Mode m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
1405              int rev = 0;
1406              p = _pos_get(wd, &rev, &m);
1407              _flip_do(wd->obj, p, m, 1, rev);
1408           }
1409         break;
1410       case ELM_FLIP_INTERACTION_PAGE:
1411         wd->pageflip = EINA_TRUE;
1412         _configure(data);
1413         _state_update(wd);
1414         break;
1415       default:
1416         break;
1417      }
1418    if (pos < 1.0) return ECORE_CALLBACK_RENEW;
1419
1420    wd->pageflip = EINA_FALSE;
1421    _state_end(wd);
1422    evas_object_map_enable_set(wd->front.content, 0);
1423    evas_object_map_enable_set(wd->back.content, 0);
1424    // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
1425    evas_object_resize(wd->front.content, 0, 0);
1426    evas_object_resize(wd->back.content, 0, 0);
1427    evas_smart_objects_calculate(evas_object_evas_get(wd->obj));
1428    // FIXME: end hack
1429    wd->animator = NULL;
1430    if (wd->finish) wd->state = !wd->state;
1431    flip_show_hide(wd->obj);
1432    _configure(wd->obj);
1433    wd->animator = NULL;
1434    evas_object_smart_callback_call(wd->obj, SIG_ANIMATE_DONE, NULL);
1435
1436    return ECORE_CALLBACK_CANCEL;
1437 }
1438
1439 static void
1440 _update_job(void *data)
1441 {
1442    Widget_Data *wd = data;
1443    double p;
1444    Elm_Flip_Mode m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
1445    int rev = 0;
1446
1447    wd->job = NULL;
1448    switch (wd->intmode)
1449      {
1450       case ELM_FLIP_INTERACTION_ROTATE:
1451       case ELM_FLIP_INTERACTION_CUBE:
1452         p = _pos_get(wd, &rev, &m);
1453         _flip_do(wd->obj, p, m, 1, rev);
1454         break;
1455       case ELM_FLIP_INTERACTION_PAGE:
1456         wd->pageflip = EINA_TRUE;
1457         _configure(data);
1458         _state_update(wd);
1459         break;
1460       default:
1461         break;
1462      }
1463 }
1464
1465 static void
1466 _down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1467 {
1468    Evas_Object *fl = data;
1469    Widget_Data *wd = elm_widget_data_get(fl);
1470    Evas_Event_Mouse_Down *ev = event_info;
1471    Evas_Coord x, y, w, h;
1472
1473    if (!wd) return;
1474    if (ev->button != 1) return;
1475    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1476    if (wd->animator)
1477      {
1478         ecore_animator_del(wd->animator);
1479         wd->animator = NULL;
1480      }
1481    wd->down = EINA_TRUE;
1482    wd->started = EINA_FALSE;
1483    evas_object_geometry_get(data, &x, &y, &w, &h);
1484    wd->x = ev->canvas.x - x;
1485    wd->y = ev->canvas.y - y;
1486    wd->w = w;
1487    wd->h = h;
1488    wd->down_x = wd->x;
1489    wd->down_y = wd->y;
1490 }
1491
1492 static void
1493 _up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1494 {
1495    Evas_Object *fl = data;
1496    Widget_Data *wd = elm_widget_data_get(fl);
1497    Evas_Event_Mouse_Up *ev = event_info;
1498    Evas_Coord x, y, w, h;
1499    double tm = 0.5;
1500
1501    if (!wd) return;
1502    if (ev->button != 1) return;
1503    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1504    wd->down = 0;
1505    evas_object_geometry_get(data, &x, &y, &w, &h);
1506    wd->x = ev->canvas.x - x;
1507    wd->y = ev->canvas.y - y;
1508    wd->w = w;
1509    wd->h = h;
1510    wd->ox = wd->x;
1511    wd->oy = wd->y;
1512    if (wd->job)
1513      {
1514         ecore_job_del(wd->job);
1515         wd->job = NULL;
1516      }
1517    wd->finish = EINA_FALSE;
1518    if (wd->dir == 0)
1519      {
1520         tm = (double)wd->x / (double)wd->w;
1521         if (wd->x < (wd->w / 2)) wd->finish = EINA_TRUE;
1522      }
1523    else if (wd->dir == 1)
1524      {
1525         if (wd->x > (wd->w / 2)) wd->finish = EINA_TRUE;
1526         tm = 1.0 - ((double)wd->x / (double)wd->w);
1527      }
1528    else if (wd->dir == 2)
1529      {
1530         if (wd->y < (wd->h / 2)) wd->finish = EINA_TRUE;
1531         tm = (double)wd->y / (double)wd->h;
1532      }
1533    else if (wd->dir == 3)
1534      {
1535         if (wd->y > (wd->h / 2)) wd->finish = EINA_TRUE;
1536         tm = 1.0 - ((double)wd->y / (double)wd->h);
1537      }
1538    if (tm < 0.01) tm = 0.01;
1539    else if (tm > 0.99) tm = 0.99;
1540    if (!wd->finish) tm = 1.0 - tm;
1541    tm *= 1.0; // FIXME: config for anim time
1542    if (wd->animator) ecore_animator_del(wd->animator);
1543    wd->animator = ecore_animator_timeline_add(tm, _event_anim, wd);
1544    _event_anim(wd, 0.0);
1545 }
1546
1547 static void
1548 _move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1549 {
1550    Evas_Object *fl = data;
1551    Widget_Data *wd = elm_widget_data_get(fl);
1552    Evas_Event_Mouse_Move *ev = event_info;
1553    Evas_Coord x, y, w, h;
1554
1555    if (!wd) return;
1556    if (!wd->down) return;
1557    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1558    evas_object_geometry_get(data, &x, &y, &w, &h);
1559    wd->x = ev->cur.canvas.x - x;
1560    wd->y = ev->cur.canvas.y - y;
1561    wd->w = w;
1562    wd->h = h;
1563    if (!wd->started)
1564      {
1565         Evas_Coord dx, dy;
1566
1567         dx = wd->x - wd->down_x;
1568         dy = wd->y - wd->down_y;
1569         if (((dx * dx) + (dy * dy)) > (_elm_config->finger_size * _elm_config->finger_size / 4))
1570           {
1571              wd->dir = 0;
1572              if      ((wd->x > (w / 2)) && (dx <  0) && (abs(dx) >  abs(dy))) wd->dir = 0; // left
1573              else if ((wd->x < (w / 2)) && (dx >= 0) && (abs(dx) >  abs(dy))) wd->dir = 1; // right
1574              else if ((wd->y > (h / 2)) && (dy <  0) && (abs(dy) >= abs(dx))) wd->dir = 2; // up
1575              else if ((wd->y < (h / 2)) && (dy >= 0) && (abs(dy) >= abs(dx))) wd->dir = 3; // down
1576              wd->started = EINA_TRUE;
1577              if (wd->intmode == ELM_FLIP_INTERACTION_PAGE)
1578                 wd->pageflip = EINA_TRUE;
1579              flip_show_hide(data);
1580              evas_smart_objects_calculate(evas_object_evas_get(data));
1581              _flip(data);
1582              // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow)
1583              evas_object_map_enable_set(wd->front.content, 0);
1584              evas_object_map_enable_set(wd->back.content, 0);
1585 // FIXME: XXX why does this bork interactive flip??
1586 //             evas_object_resize(wd->front.content, 0, 0);
1587 //             evas_object_resize(wd->back.content, 0, 0);
1588              evas_smart_objects_calculate(evas_object_evas_get(data));
1589              _configure(obj);
1590              // FIXME: end hack
1591              evas_object_smart_callback_call(obj, SIG_ANIMATE_BEGIN, NULL);
1592           }
1593         else return;
1594      }
1595    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1596    if (wd->job) ecore_job_del(wd->job);
1597    wd->job = ecore_job_add(_update_job, wd);
1598 }
1599
1600 /**
1601  * Add a new flip to the parent
1602  *
1603  * @param parent The parent object
1604  * @return The new object or NULL if it cannot be created
1605  *
1606  * @ingroup Flip
1607  */
1608 EAPI Evas_Object *
1609 elm_flip_add(Evas_Object *parent)
1610 {
1611    Evas_Object *obj;
1612    Evas *e;
1613    Widget_Data *wd;
1614
1615    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1616
1617    ELM_SET_WIDTYPE(widtype, "flip");
1618    elm_widget_type_set(obj, "flip");
1619    elm_widget_sub_object_add(parent, obj);
1620    elm_widget_data_set(obj, wd);
1621    elm_widget_del_hook_set(obj, _del_hook);
1622    elm_widget_theme_hook_set(obj, _theme_hook);
1623    elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
1624    elm_widget_can_focus_set(obj, EINA_FALSE);
1625
1626    wd->obj = obj;
1627
1628    wd->clip = evas_object_rectangle_add(e);
1629    evas_object_static_clip_set(wd->clip, 1);
1630    evas_object_color_set(wd->clip, 255, 255, 255, 255);
1631    evas_object_move(wd->clip, -49999, -49999);
1632    evas_object_resize(wd->clip, 99999, 99999);
1633    elm_widget_sub_object_add(obj, wd->clip);
1634    evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
1635    evas_object_smart_member_add(wd->clip, obj);
1636
1637    wd->front.clip = evas_object_rectangle_add(e);
1638    evas_object_static_clip_set(wd->front.clip, 1);
1639    evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
1640    evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
1641    evas_object_move(wd->front.clip, -49999, -49999);
1642    evas_object_resize(wd->front.clip, 99999, 99999);
1643    elm_widget_sub_object_add(obj, wd->front.clip);
1644    evas_object_smart_member_add(wd->front.clip, obj);
1645    evas_object_clip_set(wd->front.clip, wd->clip);
1646
1647    wd->back.clip = evas_object_rectangle_add(e);
1648    evas_object_static_clip_set(wd->back.clip, 1);
1649    evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
1650    evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
1651    evas_object_move(wd->back.clip, -49999, -49999);
1652    evas_object_resize(wd->back.clip, 99999, 99999);
1653    elm_widget_sub_object_add(wd->back.clip, obj);
1654    evas_object_smart_member_add(obj, wd->back.clip);
1655    evas_object_clip_set(wd->back.clip, wd->clip);
1656
1657    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
1658    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
1659    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
1660
1661    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1662
1663    wd->state = 1;
1664    wd->intmode = ELM_FLIP_INTERACTION_NONE;
1665
1666    _sizing_eval(obj);
1667
1668    return obj;
1669 }
1670
1671 /**
1672  * Set the front content of the flip widget.
1673  *
1674  * Once the content object is set, a previously set one will be deleted.
1675  * If you want to keep that old content object, use the
1676  * elm_flip_content_front_unset() function.
1677  *
1678  * @param obj The flip object
1679  * @param content The new front content object
1680  *
1681  * @ingroup Flip
1682  */
1683 EAPI void
1684 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
1685 {
1686    ELM_CHECK_WIDTYPE(obj, widtype);
1687    Widget_Data *wd = elm_widget_data_get(obj);
1688    int i;
1689    if (!wd) return;
1690    if (wd->front.content == content) return;
1691    if (wd->front.content) evas_object_del(wd->back.content);
1692    wd->front.content = content;
1693    if (content)
1694      {
1695         elm_widget_sub_object_add(obj, content);
1696         evas_object_smart_member_add(content, obj);
1697         evas_object_clip_set(content, wd->front.clip);
1698         evas_object_event_callback_add(content,
1699                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1700                                        _changed_size_hints, obj);
1701         _sizing_eval(obj);
1702      }
1703    // force calc to contents are the right size before transition
1704    evas_smart_objects_calculate(evas_object_evas_get(obj));
1705    flip_show_hide(obj);
1706    _configure(obj);
1707    if (wd->intmode != ELM_FLIP_INTERACTION_NONE)
1708      {
1709         for (i = 0; i < 4; i++) evas_object_raise(wd->event[i]);
1710      }
1711 }
1712
1713 /**
1714  * Set the back content of the flip widget.
1715  *
1716  * Once the content object is set, a previously set one will be deleted.
1717  * If you want to keep that old content object, use the
1718  * elm_flip_content_back_unset() function.
1719  *
1720  * @param obj The flip object
1721  * @param content The new back content object
1722  *
1723  * @ingroup Flip
1724  */
1725 EAPI void
1726 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
1727 {
1728    ELM_CHECK_WIDTYPE(obj, widtype);
1729    Widget_Data *wd = elm_widget_data_get(obj);
1730    int i;
1731    if (!wd) return;
1732    if (wd->back.content == content) return;
1733    if (wd->back.content) evas_object_del(wd->back.content);
1734    wd->back.content = content;
1735    if (content)
1736      {
1737         elm_widget_sub_object_add(obj, content);
1738         evas_object_smart_member_add(content, obj);
1739         evas_object_clip_set(content, wd->back.clip);
1740         evas_object_event_callback_add(content,
1741                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1742                                        _changed_size_hints, obj);
1743         _sizing_eval(obj);
1744      }
1745    // force calc to contents are the right size before transition
1746    evas_smart_objects_calculate(evas_object_evas_get(obj));
1747    flip_show_hide(obj);
1748    _configure(obj);
1749    if (wd->intmode != ELM_FLIP_INTERACTION_NONE)
1750      {
1751         for (i = 0; i < 4; i++) evas_object_raise(wd->event[i]);
1752      }
1753 }
1754
1755 /**
1756  * Get the front content used for the flip
1757  *
1758  * Return the front content object which is set for this widget.
1759  *
1760  * @param obj The flip object
1761  * @return The front content object that is being used
1762  *
1763  * @ingroup Flip
1764  */
1765 EAPI Evas_Object *
1766 elm_flip_content_front_get(const Evas_Object *obj)
1767 {
1768    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1769    Widget_Data *wd = elm_widget_data_get(obj);
1770    return wd->front.content;
1771 }
1772
1773
1774 /**
1775  * Get the back content used for the flip
1776  *
1777  * Return the back content object which is set for this widget.
1778  *
1779  * @param obj The flip object
1780  * @return The back content object that is being used
1781  *
1782  * @ingroup Flip
1783  */
1784 EAPI Evas_Object *
1785 elm_flip_content_back_get(const Evas_Object *obj)
1786 {
1787    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1788    Widget_Data *wd = elm_widget_data_get(obj);
1789    return wd->back.content;
1790 }
1791
1792 /**
1793  * Unset the front content used for the flip
1794  *
1795  * Unparent and return the front content object which was set for this widget.
1796  *
1797  * @param obj The flip object
1798  * @return The front content object that was being used
1799  *
1800  * @ingroup Flip
1801  */
1802 EAPI Evas_Object *
1803 elm_flip_content_front_unset(Evas_Object *obj)
1804 {
1805    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1806    Widget_Data *wd = elm_widget_data_get(obj);
1807    if (!wd) return NULL;
1808    if (!wd->front.content) return NULL;
1809    Evas_Object *content = wd->front.content;
1810    evas_object_clip_unset(content);
1811    elm_widget_sub_object_del(obj, content);
1812    evas_object_smart_member_del(content);
1813    wd->front.content = NULL;
1814    return content;
1815 }
1816
1817 /**
1818  * Unset the back content used for the flip
1819  *
1820  * Unparent and return the back content object which was set for this widget.
1821  *
1822  * @param obj The flip object
1823  * @return The back content object that was being used
1824  *
1825  * @ingroup Flip
1826  */
1827 EAPI Evas_Object *
1828 elm_flip_content_back_unset(Evas_Object *obj)
1829 {
1830    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1831    Widget_Data *wd = elm_widget_data_get(obj);
1832    if (!wd) return NULL;
1833    if (!wd->back.content) return NULL;
1834    Evas_Object *content = wd->back.content;
1835    evas_object_clip_unset(content);
1836    elm_widget_sub_object_del(obj, content);
1837    evas_object_smart_member_del(content);
1838    wd->back.content = NULL;
1839    return content;
1840 }
1841
1842 /**
1843  * Get flip front visibility state
1844  *
1845  * @param obj The flip object
1846  * @return If front front is showing or not currently
1847  *
1848  * @ingroup Flip
1849  */
1850 EAPI Eina_Bool
1851 elm_flip_front_get(const Evas_Object *obj)
1852 {
1853    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1854    Widget_Data *wd = elm_widget_data_get(obj);
1855    if (!wd) return EINA_FALSE;
1856    return wd->state;
1857 }
1858
1859 /**
1860  * Set flip perspective
1861  *
1862  * @param obj The flip object
1863  * @param foc The coordinate to set the focus on
1864  * @param x The X coordinate
1865  * @param y The Y coordinate
1866  *
1867  * NOTE: This function currently does nothing.
1868  *
1869  * @ingroup Flip
1870  */
1871 EAPI void
1872 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
1873 {
1874    ELM_CHECK_WIDTYPE(obj, widtype);
1875    Widget_Data *wd = elm_widget_data_get(obj);
1876    if (!wd) return;
1877 }
1878
1879 // FIXME: add ambient and lighting control
1880
1881 /**
1882  * Runs the flip animation
1883  *
1884  * @param obj The flip object
1885  * @param mode The mode type
1886  *
1887  * @ingroup Flip
1888  */
1889 EAPI void
1890 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
1891 {
1892    ELM_CHECK_WIDTYPE(obj, widtype);
1893    Widget_Data *wd = elm_widget_data_get(obj);
1894    if (!wd) return;
1895    if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
1896    flip_show_hide(obj);
1897    wd->mode = mode;
1898    wd->start = ecore_loop_time_get();
1899    wd->len = 0.5; // FIXME: make config val
1900    if ((wd->mode == ELM_FLIP_PAGE_LEFT) ||
1901        (wd->mode == ELM_FLIP_PAGE_RIGHT) ||
1902        (wd->mode == ELM_FLIP_PAGE_UP) ||
1903        (wd->mode == ELM_FLIP_PAGE_DOWN))
1904       wd->pageflip = EINA_TRUE;
1905    // force calc to contents are the right size before transition
1906    evas_smart_objects_calculate(evas_object_evas_get(obj));
1907    _flip(obj);
1908    // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow)
1909    evas_object_map_enable_set(wd->front.content, 0);
1910    evas_object_map_enable_set(wd->back.content, 0);
1911    evas_object_resize(wd->front.content, 0, 0);
1912    evas_object_resize(wd->back.content, 0, 0);
1913    evas_smart_objects_calculate(evas_object_evas_get(obj));
1914    _configure(obj);
1915    // FIXME: end hack
1916    evas_object_smart_callback_call(obj, SIG_ANIMATE_BEGIN, NULL);
1917 }
1918
1919 /**
1920  * Set the interactive flip mode
1921  *
1922  * @param obj The flip object
1923  * @param mode The interactive flip mode to use
1924  *
1925  * This sets if the flip should be interactive (allow user to click and
1926  * drag a side of the flip to reveal the back page and cause it to flip).
1927  * By default a flip is not interactive. You may also need to set which
1928  * sides of the flip are "active" for flipping and how much space they use
1929  * (a minimum of a finger size) with elm_flip_interacton_direction_enabled_set()
1930  * and elm_flip_interacton_direction_hitsize_set()
1931  *
1932  * @ingroup Flip
1933  */
1934 EAPI void
1935 elm_flip_interaction_set(Evas_Object *obj, Elm_Flip_Interaction mode)
1936 {
1937    ELM_CHECK_WIDTYPE(obj, widtype);
1938    int i;
1939    Widget_Data *wd = elm_widget_data_get(obj);
1940    if (!wd) return;
1941    if (wd->intmode == mode) return;
1942    wd->intmode = mode;
1943    for (i = 0; i < 4; i++)
1944      {
1945         if (wd->intmode == ELM_FLIP_INTERACTION_NONE)
1946           {
1947              if (wd->event[i])
1948                {
1949                   evas_object_del(wd->event[i]);
1950                   wd->event[i] = NULL;
1951                }
1952           }
1953         else
1954           {
1955              if ((wd->dir_enabled[i]) && (!wd->event[i]))
1956                {
1957                   wd->event[i] = evas_object_rectangle_add(evas_object_evas_get(obj));
1958                   elm_widget_sub_object_add(obj, wd->event[i]);
1959                   evas_object_clip_set(wd->event[i], evas_object_clip_get(obj));
1960                   evas_object_color_set(wd->event[i], 0, 0, 0, 0);
1961                   evas_object_show(wd->event[i]);
1962                   evas_object_smart_member_add(wd->event[i], obj);
1963                   evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_DOWN, _down_cb, obj);
1964                   evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_UP, _up_cb, obj);
1965                   evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_MOVE, _move_cb, obj);
1966                }
1967           }
1968      }
1969    _sizing_eval(obj);
1970    _configure(obj);
1971 }
1972
1973 /**
1974  * Get the interactive flip mode
1975  *
1976  * @param obj The flip object
1977  * @return The interactive flip mode
1978  *
1979  * Returns the interactive flip mode set by elm_flip_interaction_set()
1980  *
1981  * @ingroup Flip
1982  */
1983 EAPI Elm_Flip_Interaction
1984 elm_flip_interaction_get(const Evas_Object *obj)
1985 {
1986    ELM_CHECK_WIDTYPE(obj, widtype) ELM_FLIP_INTERACTION_NONE;
1987    Widget_Data *wd = elm_widget_data_get(obj);
1988    if (!wd) return ELM_FLIP_INTERACTION_NONE;
1989    return wd->intmode;
1990 }
1991
1992 /**
1993  * Set which directions of the flip respond to interactive flip
1994  *
1995  * @param obj The flip object
1996  * @param dir The direction to change
1997  * @param enabled If that direction is enabled or not
1998  *
1999  * By default all directions are disabled, so you may want to enable the
2000  * desired directions for flipping if you need interactive flipping.
2001  *
2002  * @ingroup Flip
2003  */
2004 EAPI void
2005 elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction dir, Eina_Bool enabled)
2006 {
2007    ELM_CHECK_WIDTYPE(obj, widtype);
2008    Widget_Data *wd = elm_widget_data_get(obj);
2009    int i = -1;
2010    if (!wd) return;
2011    enabled = !!enabled;
2012    if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
2013    else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
2014    else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
2015    else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
2016    if (i < 0) return;
2017    if (wd->dir_enabled[i] == enabled) return;
2018    wd->dir_enabled[i] = enabled;
2019    if (wd->intmode == ELM_FLIP_INTERACTION_NONE) return;
2020    if ((wd->dir_enabled[i]) && (!wd->event[i]))
2021      {
2022         wd->event[i] = evas_object_rectangle_add(evas_object_evas_get(obj));
2023         elm_widget_sub_object_add(obj, wd->event[i]);
2024         evas_object_clip_set(wd->event[i], evas_object_clip_get(obj));
2025         evas_object_color_set(wd->event[i], 0, 0, 0, 0);
2026         evas_object_show(wd->event[i]);
2027         evas_object_smart_member_add(wd->event[i], obj);
2028         evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_DOWN, _down_cb, obj);
2029         evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_UP, _up_cb, obj);
2030         evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_MOVE, _move_cb, obj);
2031      }
2032    else if (!(wd->dir_enabled[i]) && (wd->event[i]))
2033      {
2034         evas_object_del(wd->event[i]);
2035         wd->event[i] = NULL;
2036      }
2037    _sizing_eval(obj);
2038    _configure(obj);
2039 }
2040
2041 /**
2042  * Get the enabled state of that flip direction
2043  *
2044  * @param obj The flip object
2045  * @param dir The direction to check
2046  * @return If that direction is enabled or not
2047  *
2048  * Gets the enabled state set by elm_flip_interacton_direction_enabled_set()
2049  *
2050  * @ingroup Flip
2051  */
2052 EAPI Eina_Bool
2053 elm_flip_interacton_direction_enabled_get(Evas_Object *obj, Elm_Flip_Direction dir)
2054 {
2055    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2056    Widget_Data *wd = elm_widget_data_get(obj);
2057    int i = -1;
2058    if (!wd) return EINA_FALSE;
2059    if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
2060    else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
2061    else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
2062    else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
2063    if (i < 0) return EINA_FALSE;
2064    return wd->dir_enabled[i];
2065 }
2066
2067 /**
2068  * Set the amount of the flip that is sensitive to interactive flip
2069  *
2070  * @param obj The flip object
2071  * @param dir The direction to modify
2072  * @param hitsize The amount of that dimension (0.0 to 1.0) to use
2073  *
2074  * @ingroup Flip
2075  */
2076 EAPI void
2077 elm_flip_interacton_direction_hitsize_set(Evas_Object *obj, Elm_Flip_Direction dir, double hitsize)
2078 {
2079    ELM_CHECK_WIDTYPE(obj, widtype);
2080    Widget_Data *wd = elm_widget_data_get(obj);
2081    int i = -1;
2082    if (!wd) return;
2083    if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
2084    else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
2085    else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
2086    else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
2087    if (i < 0) return;
2088    if (hitsize < 0.0) hitsize = 0.0;
2089    else if (hitsize > 1.0) hitsize = 1.0;
2090    if (wd->dir_hitsize[i] == hitsize) return;
2091    wd->dir_hitsize[i] = hitsize;
2092    _sizing_eval(obj);
2093    _configure(obj);
2094 }
2095
2096 /**
2097  * Get the amount of the flip that is sensitive to interactive flip
2098  *
2099  * @param obj The flip object
2100  * @param dir The direction to check
2101  * @return The size set for that direction
2102  *
2103  * Returns the amount os sensitive area set by elm_flip_interacton_direction_hitsize_set().
2104  *
2105  * @ingroup Flip
2106  */
2107 EAPI double
2108 elm_flip_interacton_direction_hitsize_get(Evas_Object *obj, Elm_Flip_Direction dir)
2109 {
2110    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2111    Widget_Data *wd = elm_widget_data_get(obj);
2112    int i = -1;
2113    if (!wd) return 0.0;
2114    if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
2115    else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
2116    else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
2117    else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
2118    if (i < 0) return 0.0;
2119    return wd->dir_hitsize[i];
2120 }