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