and... flip now does interactive flipping.. AND page curl flips...
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 25 May 2011 10:20:49 +0000 (10:20 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 25 May 2011 10:20:49 +0000 (10:20 +0000)
woooo!

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@59662 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/test_flip.c
src/lib/Elementary.h.in
src/lib/elm_flip.c

index 731bbd2..b5ae4f7 100644 (file)
@@ -492,17 +492,28 @@ test_flip3(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    evas_object_show(win);
 }
 
+
 static void
 my_fl_go(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   Evas_Object *fl = data;
-   elm_flip_go(fl, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
+   Evas_Object *win = data;
+   Evas_Object *fl = evas_object_data_get(win, "fl");
+   elm_flip_go(fl, ELM_FLIP_PAGE_LEFT);
+}
+
+static void
+my_fl_ch(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Evas_Object *win = data;
+   Evas_Object *fl = evas_object_data_get(win, "fl");
+   Evas_Object *rdg = evas_object_data_get(win, "rdg");
+   elm_flip_interaction_set(fl, elm_radio_value_get(rdg));
 }
 
 void
 test_flip4(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   Evas_Object *win, *bg, *bx, *fl, *im, *li, *bt;
+   Evas_Object *win, *bg, *bx, *fl, *im, *li, *bt, *rd, *rdg;
    char buf[PATH_MAX];
 
    win = elm_win_add(NULL, "flip4", ELM_WIN_BASIC);
@@ -523,12 +534,17 @@ test_flip4(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    evas_object_size_hint_align_set(fl, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(fl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    elm_box_pack_end(bx, fl);
+   evas_object_data_set(win, "fl", fl);
    
-   elm_flip_interaction_set(fl, ELM_FLIP_INTERACTION_CUBE);
+   elm_flip_interaction_set(fl, ELM_FLIP_INTERACTION_NONE);
    elm_flip_interacton_direction_enabled_set(fl, ELM_FLIP_DIRECTION_UP, EINA_TRUE);
    elm_flip_interacton_direction_enabled_set(fl, ELM_FLIP_DIRECTION_DOWN, EINA_TRUE);
    elm_flip_interacton_direction_enabled_set(fl, ELM_FLIP_DIRECTION_LEFT, EINA_TRUE);
    elm_flip_interacton_direction_enabled_set(fl, ELM_FLIP_DIRECTION_RIGHT, EINA_TRUE);
+   elm_flip_interacton_direction_hitsize_set(fl, ELM_FLIP_DIRECTION_UP, 0.25);
+   elm_flip_interacton_direction_hitsize_set(fl, ELM_FLIP_DIRECTION_DOWN, 0.25);
+   elm_flip_interacton_direction_hitsize_set(fl, ELM_FLIP_DIRECTION_LEFT, 0.25);
+   elm_flip_interacton_direction_hitsize_set(fl, ELM_FLIP_DIRECTION_RIGHT, 0.25);
    evas_object_show(fl);
 
    im = evas_object_image_filled_add(evas_object_evas_get(win));
@@ -538,7 +554,16 @@ test_flip4(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    evas_object_image_file_set(im, buf, NULL);
    elm_flip_content_front_set(fl, im);
    evas_object_show(im);
-   
+
+#if 0
+   im = evas_object_image_filled_add(evas_object_evas_get(win));
+   evas_object_size_hint_weight_set(im, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   snprintf(buf, sizeof(buf), "%s/images/%s",
+            PACKAGE_DATA_DIR, "sky_04.jpg");
+   evas_object_image_file_set(im, buf, NULL);
+   elm_flip_content_back_set(fl, im);
+   evas_object_show(im);
+#else   
    li = elm_list_add(win);
    evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    elm_list_item_append(li, "Item 0", NULL, NULL, NULL, NULL);
@@ -548,10 +573,52 @@ test_flip4(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    elm_list_go(li);
    elm_flip_content_back_set(fl, li);
    evas_object_show(li);
+#endif
+
+   rd = elm_radio_add(win);
+   evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0);
+   elm_radio_state_value_set(rd, ELM_FLIP_INTERACTION_NONE);
+   elm_radio_label_set(rd, "None");
+   elm_box_pack_end(bx, rd);
+   evas_object_show(rd);
+   evas_object_smart_callback_add(rd, "changed", my_fl_ch, win);
+   rdg = rd;
+   evas_object_data_set(win, "rdg", rdg);
+   
+   rd = elm_radio_add(win);
+   evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0);
+   elm_radio_state_value_set(rd, ELM_FLIP_INTERACTION_ROTATE);
+   elm_radio_label_set(rd, "Rotate");
+   elm_radio_group_add(rd, rdg);
+   elm_box_pack_end(bx, rd);
+   evas_object_show(rd);
+   evas_object_smart_callback_add(rd, "changed", my_fl_ch, win);
    
+   rd = elm_radio_add(win);
+   evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0);
+   elm_radio_state_value_set(rd, ELM_FLIP_INTERACTION_CUBE);
+   elm_radio_label_set(rd, "Cube");
+   elm_radio_group_add(rd, rdg);
+   elm_box_pack_end(bx, rd);
+   evas_object_show(rd);
+   evas_object_smart_callback_add(rd, "changed", my_fl_ch, win);
+   
+   rd = elm_radio_add(win);
+   evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0);
+   elm_radio_state_value_set(rd, ELM_FLIP_INTERACTION_PAGE);
+   elm_radio_label_set(rd, "Page");
+   elm_radio_group_add(rd, rdg);
+   elm_box_pack_end(bx, rd);
+   evas_object_show(rd);
+   evas_object_smart_callback_add(rd, "changed", my_fl_ch, win);
+
    bt = elm_button_add(win);
    elm_button_label_set(bt, "Go");
-   evas_object_smart_callback_add(bt, "clicked", my_fl_go, fl);
+   evas_object_smart_callback_add(bt, "clicked", my_fl_go, win);
    evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
    elm_box_pack_end(bx, bt);
index 7b6c73b..d49fc59 100644 (file)
@@ -2492,7 +2492,11 @@ extern "C" {
         ELM_FLIP_CUBE_LEFT,
         ELM_FLIP_CUBE_RIGHT,
         ELM_FLIP_CUBE_UP,
-        ELM_FLIP_CUBE_DOWN
+        ELM_FLIP_CUBE_DOWN,
+        ELM_FLIP_PAGE_LEFT,
+        ELM_FLIP_PAGE_RIGHT,
+        ELM_FLIP_PAGE_UP,
+        ELM_FLIP_PAGE_DOWN
      } Elm_Flip_Mode;
    typedef enum _Elm_Flip_Interaction
      {
@@ -2523,7 +2527,10 @@ extern "C" {
    EAPI Elm_Flip_Interaction elm_flip_interaction_get(const Evas_Object *obj);
    EAPI void         elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction dir, Eina_Bool enabled);
    EAPI Eina_Bool    elm_flip_interacton_direction_enabled_get(Evas_Object *obj, Elm_Flip_Direction dir);
+   EAPI void         elm_flip_interacton_direction_hitsize_set(Evas_Object *obj, Elm_Flip_Direction dir, double hitsize);
+   EAPI double       elm_flip_interacton_direction_hitsize_get(Evas_Object *obj, Elm_Flip_Direction dir);
    /* smart callbacks called:
+    * "animate,begin" - when a flip animation was started
     * "animate,done" - when a flip animation is finished
     */
 
index 2ccbd9d..764ba9d 100644 (file)
  * ELM_FLIP_CUBE_RIGHT
  * ELM_FLIP_CUBE_UP
  * ELM_FLIP_CUBE_DOWN
+ * ELM_FLIP_PAGE_LEFT
+ * ELM_FLIP_PAGE_RIGHT
+ * ELM_FLIP_PAGE_UP
+ * ELM_FLIP_PAGE_DOWN
  *
  * Signals that you can add callbacks for are:
  *
  */
 
 typedef struct _Widget_Data Widget_Data;
+typedef struct _Slice Slice;
+typedef struct _Vertex2 Vertex2;
+typedef struct _Vertex3 Vertex3;
+
+struct _Slice
+{
+   Evas_Object *obj;
+   double u[4], v[4], x[4], y[4], z[4];
+};
+
+struct _Vertex2
+{
+   double x, y;
+};
+
+struct _Vertex3
+{
+   double x, y, z;
+};
 
 struct _Widget_Data
 {
@@ -39,11 +62,17 @@ struct _Widget_Data
    Evas_Coord down_x, down_y, x, y, ox, oy, w, h;
    Elm_Flip_Interaction intmode;
    int dir;
+   double    dir_hitsize[4];
    Eina_Bool dir_enabled[4];
+   int slices_w, slices_h;
+   Slice **slices, **slices2;
+   
    Eina_Bool state : 1;
    Eina_Bool down : 1;
    Eina_Bool finish : 1;
    Eina_Bool started : 1;
+   Eina_Bool backflip : 1;
+   Eina_Bool pageflip : 1;
 };
 
 static const char *widtype = NULL;
@@ -53,11 +82,14 @@ static void _sizing_eval(Evas_Object *obj);
 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
 
+static void _state_slices_clear(Widget_Data *st);
 static void _configure(Evas_Object *obj);
 
+static const char SIG_ANIMATE_BEGIN[] = "animate,begin";
 static const char SIG_ANIMATE_DONE[] = "animate,done";
 
 static const Evas_Smart_Cb_Description _signals[] = {
+   {SIG_ANIMATE_BEGIN, ""},
    {SIG_ANIMATE_DONE, ""},
    {NULL, NULL}
 };
@@ -68,6 +100,7 @@ _del_hook(Evas_Object *obj)
    Widget_Data *wd = elm_widget_data_get(obj);
    if (!wd) return;
    if (wd->animator) ecore_animator_del(wd->animator);
+   _state_slices_clear(wd);
    free(wd);
 }
 
@@ -160,31 +193,692 @@ _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
      }
 }
 
+static Slice *
+_slice_new(Widget_Data *st __UNUSED__, Evas_Object *obj)
+{
+   Slice *sl;
+   
+   sl = calloc(1, sizeof(Slice));
+   if (!sl) return NULL;
+   sl->obj = evas_object_image_add(evas_object_evas_get(obj));
+   elm_widget_sub_object_add(st->obj, sl->obj);
+   evas_object_clip_set(sl->obj, evas_object_clip_get(st->obj));
+   evas_object_smart_member_add(sl->obj, st->obj);
+   evas_object_image_smooth_scale_set(sl->obj, 0);
+   evas_object_pass_events_set(sl->obj, 1);
+   evas_object_image_source_set(sl->obj, obj);
+   return sl;
+}
+
+static void
+_slice_free(Slice *sl)
+{
+   evas_object_del(sl->obj);
+   free(sl);
+}
+
+static void
+_slice_apply(Widget_Data *st, Slice *sl,
+             Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__, Evas_Coord w, Evas_Coord h __UNUSED__,
+             Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
+{
+   Evas_Map *m;
+   int i;
+   
+   m = evas_map_new(4);
+   if (!m) return;
+   evas_map_smooth_set(m, 0);
+   for (i = 0; i < 4; i++)
+     {
+        evas_map_point_color_set(m, i, 255, 255, 255, 255);
+        if (st->dir == 0)
+          {
+             int p[4] = { 0, 1, 2, 3 };
+             evas_map_point_coord_set(m, i, ox + sl->x[p[i]], oy + sl->y[p[i]], sl->z[p[i]]);
+             evas_map_point_image_uv_set(m, i, sl->u[p[i]] , sl->v[p[i]]);
+          }
+        else if (st->dir == 1)
+          {
+             int p[4] = { 1, 0, 3, 2 };
+             evas_map_point_coord_set(m, i, ox + (w - sl->x[p[i]]), oy + sl->y[p[i]], sl->z[p[i]]);
+             evas_map_point_image_uv_set(m, i, ow - sl->u[p[i]] , sl->v[p[i]]);
+          }
+        else if (st->dir == 2)
+          {
+             int p[4] = { 1, 0, 3, 2 };
+             evas_map_point_coord_set(m, i, ox + sl->y[p[i]], oy + sl->x[p[i]], sl->z[p[i]]);
+             evas_map_point_image_uv_set(m, i, sl->v[p[i]] , sl->u[p[i]]);
+          }
+        else if (st->dir == 3)
+          {
+             int p[4] = { 0, 1, 2, 3 };
+             evas_map_point_coord_set(m, i, ox + sl->y[p[i]], oy + (w - sl->x[p[i]]), sl->z[p[i]]);
+             evas_map_point_image_uv_set(m, i, sl->v[p[i]] , oh - sl->u[p[i]]);
+          }
+     }
+   evas_object_map_enable_set(sl->obj, EINA_TRUE);
+   evas_object_image_fill_set(sl->obj, 0, 0, ow, oh);
+   evas_object_map_set(sl->obj, m);
+   evas_map_free(m);
+}
+
+static void
+_slice_3d(Widget_Data *st __UNUSED__, Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+   Evas_Map *m = (Evas_Map *)evas_object_map_get(sl->obj);
+   int i;
+   
+   if (!m) return;
+   // vanishing point is center of page, and focal dist is 1024
+   evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 1024);
+   for (i = 0; i < 4; i++)
+     {
+        Evas_Coord x, y, z;
+        evas_map_point_coord_get(m, i, &x, &y, &z);
+        evas_map_point_coord_set(m, i, x, y, 0);
+     }
+   if (evas_map_util_clockwise_get(m)) evas_object_show(sl->obj);
+   else evas_object_hide(sl->obj);
+   evas_object_map_set(sl->obj, m);
+}
+
+static void
+_slice_light(Widget_Data *st __UNUSED__, Slice *sl, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+   Evas_Map *m = (Evas_Map *)evas_object_map_get(sl->obj);
+   int i;
+   
+   if (!m) return;
+   evas_map_util_3d_lighting(m,
+                             // light position
+                             // (centered over page 10 * h toward camera)
+                             x + (w / 2)  , y + (h / 2)  , -10000,
+                             255, 255, 255, // light color
+                             0 , 0 , 0); // ambient minimum
+   // multiply brightness by 1.2 to make lightish bits all white so we dont
+   // add shading where we could otherwise be pure white
+   for (i = 0; i < 4; i++)
+     {
+        int r, g, b, a;
+        
+        evas_map_point_color_get(m, i, &r, &g, &b, &a);
+        r = (double)r * 1.2; if (r > 255) r = 255;
+        g = (double)g * 1.2; if (g > 255) g = 255;
+        b = (double)b * 1.2; if (b > 255) b = 255;
+        evas_map_point_color_set(m, i, r, g, b, a);
+     }
+   evas_object_map_set(sl->obj, m);
+}
+
+static void
+_slice_xyz(Widget_Data *st __UNUSED__, Slice *sl,
+           double x1, double y1, double z1,
+           double x2, double y2, double z2,
+           double x3, double y3, double z3,
+           double x4, double y4, double z4)
+{
+   sl->x[0] = x1; sl->y[0] = y1; sl->z[0] = z1;
+   sl->x[1] = x2; sl->y[1] = y2; sl->z[1] = z2;
+   sl->x[2] = x3; sl->y[2] = y3; sl->z[2] = z3;
+   sl->x[3] = x4; sl->y[3] = y4; sl->z[3] = z4;
+}
+
+static void
+_slice_uv(Widget_Data *st __UNUSED__, Slice *sl,
+          double u1, double v1,
+          double u2, double v2,
+          double u3, double v3,
+          double u4, double v4)
+{
+   sl->u[0] = u1; sl->v[0] = v1;
+   sl->u[1] = u2; sl->v[1] = v2;
+   sl->u[2] = u3; sl->v[2] = v3;
+   sl->u[3] = u4; sl->v[3] = v4;
+}
+
+static void
+_deform_point(Vertex2 *vi, Vertex3 *vo, double rho, double theta, double A)
+{
+   // ^Y
+   // |
+   // |    X
+   // +---->
+   // theta == cone angle (0 -> PI/2)
+   // A     == distance of cone apex from origin
+   // rho   == angle of cone from vertical axis (...-PI/2 to PI/2...)
+   Vertex3  v1;
+   double d, r, b;
+   
+   d = sqrt((vi->x * vi->x) + pow(vi->y - A, 2));
+   r = d * sin(theta);
+   b = asin(vi->x / d) / sin(theta);
+   
+   v1.x = r * sin(b);
+   v1.y = d + A - (r * (1 - cos(b)) * sin(theta));
+   v1.z = r * (1 - cos(b)) * cos(theta);
+   
+   vo->x = (v1.x * cos(rho)) - (v1.z * sin(rho));
+   vo->y = v1.y;
+   vo->z = (v1.x * sin(rho)) + (v1.z * cos(rho));
+}
+
+static void
+_interp_point(Vertex3 *vi1, Vertex3 *vi2, Vertex3 *vo, double v)
+{
+   vo->x = (v * vi2->x) + ((1.0 - v) * vi1->x);
+   vo->y = (v * vi2->y) + ((1.0 - v) * vi1->y);
+   vo->z = (v * vi2->z) + ((1.0 - v) * vi1->z);
+}
+
+static void
+_state_slices_clear(Widget_Data *st)
+{
+   int i, j, num;
+   
+   if (st->slices)
+     {
+        num = 0;
+        for (j = 0; j < st->slices_h; j++)
+          {
+             for (i = 0; i < st->slices_w; i++)
+               {
+                  if (st->slices[num]) _slice_free(st->slices[num]);
+                  if (st->slices2[num]) _slice_free(st->slices2[num]);
+                  num++;
+               }
+          }
+        free(st->slices);
+        free(st->slices2);
+        st->slices = NULL;
+        st->slices2 = NULL;
+     }
+   st->slices_w = 0;
+   st->slices_h = 0;
+}
+
+static int
+_slice_obj_color_sum(Slice *s, int p, int *r, int *g, int *b, int *a)
+{
+   Evas_Map *m;
+   int rr = 0, gg = 0, bb = 0, aa = 0;
+   
+   if (!s) return 0;
+   m = (Evas_Map *)evas_object_map_get(s->obj);
+   if (!m) return 0;
+   evas_map_point_color_get(m, p, &rr, &gg, &bb, &aa);
+   *r += rr; *g += gg; *b += bb; *a += aa;
+   return 1;
+}
+
+static void
+_slice_obj_color_set(Slice *s, int p, int r, int g, int b, int a)
+{
+   Evas_Map *m;
+   
+   if (!s) return;
+   m = (Evas_Map *)evas_object_map_get(s->obj);
+   if (!m) return;
+   evas_map_point_color_set(m, p, r, g, b, a);
+   evas_object_map_set(s->obj, m);
+}
+
+static void
+_slice_obj_vert_color_merge(Slice *s1, int p1, Slice *s2, int p2,
+                            Slice *s3, int p3, Slice *s4, int p4)
+{
+   int r = 0, g = 0, b = 0, a = 0, n = 0;
+   
+   n += _slice_obj_color_sum(s1, p1, &r, &g, &b, &a);
+   n += _slice_obj_color_sum(s2, p2, &r, &g, &b, &a);
+   n += _slice_obj_color_sum(s3, p3, &r, &g, &b, &a);
+   n += _slice_obj_color_sum(s4, p4, &r, &g, &b, &a);
+   
+   if (n < 1) return;
+   r /= n; g /= n; b /= n; a /= n;
+   
+   _slice_obj_color_set(s1, p1, r, g, b, a);
+   _slice_obj_color_set(s2, p2, r, g, b, a);
+   _slice_obj_color_set(s3, p3, r, g, b, a);
+   _slice_obj_color_set(s4, p4, r, g, b, a);
+}
+
+static int
+_state_update(Widget_Data *st)
+{
+   Evas_Coord x1, y1, x2, y2, mx, my;
+   Evas_Coord x, y, w, h, ox, oy, ow, oh;
+   int i, j, num, nn, jump, num2;
+   Slice *sl;
+   double b, minv = 0.0, minva, mgrad;
+   int gx, gy, gszw, gszh, gw, gh, col, row, nw, nh;
+   double rho, A, theta, perc, percm, n, rhol, Al, thetal;
+   Vertex2 *tvi;
+   Vertex3 *tvo, *tvol;
+   Evas_Object *front, *back;
+   
+   st->backflip = 1;
+   if (st->state)
+     {
+        front = st->front.content;
+        back = st->front.content;
+     }
+   else
+     {
+        front = st->back.content;
+        back = st->back.content;
+     }
+   
+   evas_object_geometry_get(st->obj, &x, &y, &w, &h);
+   ox = x; oy = y; ow = w; oh = h;
+   x1 = st->down_x;
+   y1 = st->down_y;
+   x2 = st->x;
+   y2 = st->y;
+   
+   if (st->dir == 0)
+     {
+        // no nothing. left drag is standard
+     }
+   else if (st->dir == 1)
+     {
+        x1 = (w - 1) - x1;
+        x2 = (w - 1) - x2;
+     }
+   else if (st->dir == 2)
+     {
+        Evas_Coord tmp;
+        
+        tmp = x1; x1 = y1; y1 = tmp;
+        tmp = x2; x2 = y2; y2 = tmp;
+        tmp = w; w = h; h = tmp;
+     }
+   else if (st->dir == 3)
+     {
+        Evas_Coord tmp;
+        
+        tmp = x1; x1 = y1; y1 = tmp;
+        tmp = x2; x2 = y2; y2 = tmp;
+        tmp = w; w = h; h = tmp;
+        x1 = (w - 1) - x1;
+        x2 = (w - 1) - x2;
+     }
+   
+   if (x2 >= x1) x2 = x1 - 1;
+   mx = (x1 + x2) / 2;
+   my = (y1 + y2) / 2;
+   
+   if (mx < 0) mx = 0;
+   else if (mx >= w) mx = w - 1;
+   if (my < 0) my = 0;
+   else if (my >= h) my = h - 1;
+   
+   mgrad = (double)(y1 - y2) / (double)(x1 - x2);
+   
+   if (mx < 1) mx = 1; // quick hack to keep curl line visible
+   
+   if (mgrad == 0.0) // special horizontal case
+      mgrad = 0.001; // quick dirty hack for now
+   // else
+     {
+        minv = 1.0 / mgrad;
+        // y = (m * x) + b
+        b = my + (minv * mx);
+     }
+   if ((b >= -5) && (b <= (h + 5)))
+     {
+        if (minv > 0.0) // clamp to h
+          {
+             minv = (double)(h + 5 - my) / (double)(mx);
+             b = my + (minv * mx);
+          }
+        else // clamp to 0
+          {
+             minv = (double)(-5 - my) / (double)(mx);
+             b = my + (minv * mx);
+          }
+     }
+   
+   perc = (double)x2 / (double)x1;
+   percm = (double)mx / (double)x1;
+   if (perc < 0.0) perc = 0.0;
+   else if (perc > 1.0) perc = 1.0;
+   if (percm < 0.0) percm = 0.0;
+   else if (percm > 1.0) percm = 1.0;
+   
+   minva = atan(minv) / (M_PI / 2);
+   if (minva < 0.0) minva = -minva;
+   
+   // A = apex of cone
+   if (b <= 0) A = b;
+   else A = h - b;
+   if (A < -(h * 20)) A = -h * 20;
+   //--//
+   Al = -5;
+   
+   // rho = is how much the page is turned
+   n = 1.0 - perc;
+   n = 1.0 - cos(n * M_PI / 2.0);
+   n = n * n;
+   rho = -(n * M_PI);
+   //--//
+   rhol = -(n * M_PI);
+   
+   // theta == curliness (how much page culrs in on itself
+   n = sin((1.0 - perc) * M_PI);
+   n = n * 1.2;
+   theta = 7.86 + n;
+   //--//
+   n = sin((1.0 - perc) * M_PI);
+   n = 1.0 - n;
+   n = n * n;
+   n = 1.0 - n;
+   thetal = 7.86 + n;
+   
+   nw = 16;
+   nh = 16;
+   if (nw < 1) nw = 1;
+   if (nh < 1) nh = 1;
+   gszw = w / nw;
+   gszh = h / nh;
+   if (gszw < 4) gszw = 4;
+   if (gszh < 4) gszh = 4;
+   
+   nw = (w + gszw - 1) / gszw;
+   nh = (h + gszh - 1) / gszh;
+   if ((st->slices_w != nw) || (st->slices_h != nh)) _state_slices_clear(st);
+   st->slices_w = nw;
+   st->slices_h = nh;
+   if (!st->slices)
+     {
+        st->slices = calloc(st->slices_w * st->slices_h, sizeof(Slice *));
+        if (!st->slices) return 0;
+        st->slices2 = calloc(st->slices_w * st->slices_h, sizeof(Slice *));
+        if (!st->slices2)
+          {
+             free(st->slices);
+             st->slices = NULL;
+             return 0;
+          }
+     }
+   
+   num = (st->slices_w + 1) * (st->slices_h + 1);
+   
+   tvi = alloca(sizeof(Vertex2) * num);
+   tvo = alloca(sizeof(Vertex3) * num);
+   tvol = alloca(sizeof(Vertex3) * (st->slices_w + 1));
+   
+   for (col = 0, gx = 0; gx <= (w + gszw - 1); gx += gszw, col++)
+     {
+        Vertex2 vil;
+        
+        vil.x = gx;
+        vil.y = h - ((gx * h) / (w + gszw - 1));
+        _deform_point(&vil, &(tvol[col]), rhol, thetal, Al);
+     }
+   
+   n = minva * sin(perc * M_PI);
+   n = n * n;
+   
+   num = 0;
+   for (col = 0, gx = 0; gx <= (w + gszw - 1); gx += gszw, col++)
+     {
+        for (gy = 0; gy <= (h + gszh - 1); gy += gszh)
+          {
+             Vertex2 vi;
+             Vertex3 vo, tvo1;
+             
+             if (gx > w) vi.x = w;
+             else vi.x = gx;
+             if (gy > h) vi.y = h;
+             else vi.y = gy;
+             _deform_point(&vi, &vo, rho, theta, A);
+             tvo1 = tvol[col];
+             if (gy > h) tvo1.y = h;
+             else tvo1.y = gy;
+             _interp_point(&vo, &tvo1, &(tvo[num]), n);
+             num++;
+          }
+     }
+   
+   jump = st->slices_h + 1;
+   for (col = 0, gx = 0; gx < w; gx += gszw, col++)
+     {
+        num = st->slices_h * col;
+        num2 = jump * col;
+        
+        gw = gszw;
+        if ((gx + gw) > w) gw = w - gx;
+        
+        for (row = 0, gy = 0; gy < h; gy += gszh, row++)
+          {
+             Vertex3 vo[4];
+             
+             if (b > 0) nn = num + st->slices_h - row - 1;
+             else nn = num + row;
+             
+             gh = gszh;
+             if ((gy + gh) > h) gh = h - gy;
+             
+             vo[0] = tvo[num2 + row];
+             vo[1] = tvo[num2 + row + jump];
+             vo[2] = tvo[num2 + row + jump + 1];
+             vo[3] = tvo[num2 + row + 1];
+#define SWP(a, b) do {typeof(a) vt; vt = (a); (a) = (b); (b) = vt;} while (0)
+             if (b > 0)
+               {
+                  SWP(vo[0], vo[3]);
+                  SWP(vo[1], vo[2]);
+                  vo[0].y = h - vo[0].y;
+                  vo[1].y = h - vo[1].y;
+                  vo[2].y = h - vo[2].y;
+                  vo[3].y = h - vo[3].y;
+               }
+             
+             // FRONT
+             sl = st->slices[nn];
+             if (!sl)
+               {
+                  sl = _slice_new(st, front);
+                  st->slices[nn] = sl;
+               }
+             _slice_xyz(st, sl,
+                        vo[0].x, vo[0].y, vo[0].z,
+                        vo[1].x, vo[1].y, vo[1].z,
+                        vo[2].x, vo[2].y, vo[2].z,
+                        vo[3].x, vo[3].y, vo[3].z);
+             if (b <= 0)
+                _slice_uv(st, sl,
+                          gx,       gy,       gx + gw,  gy,
+                          gx + gw,  gy + gh,  gx,       gy + gh);
+             else
+                _slice_uv(st, sl,
+                          gx,       h - (gy + gh), gx + gw,  h - (gy + gh),
+                          gx + gw,  h - gy,        gx,       h - gy);
+             
+                          // BACK
+             sl = st->slices2[nn];
+             if (!sl)
+               {
+                  sl = _slice_new(st, back);
+                  st->slices2[nn] = sl;
+               }
+             
+             _slice_xyz(st, sl,
+                        vo[1].x, vo[1].y, vo[1].z,
+                        vo[0].x, vo[0].y, vo[0].z,
+                        vo[3].x, vo[3].y, vo[3].z,
+                        vo[2].x, vo[2].y, vo[2].z);
+             if (st->backflip)
+               {
+                  if (b <= 0)
+                     _slice_uv(st, sl,
+                               gx + gw, gy,       gx,       gy,
+                               gx,      gy + gh,  gx + gw,  gy + gh);
+                  else
+                     _slice_uv(st, sl,
+                               gx + gw, h - (gy + gh), gx,      h - (gy + gh),
+                               gx,      h - gy,        gx + gw, h - gy);
+               }
+             else
+               {
+                  if (b <= 0)
+                     _slice_uv(st, sl,
+                               w - (gx + gw), gy,       w - (gx),      gy,
+                               w - (gx),      gy + gh,  w - (gx + gw), gy + gh);
+                  else
+                     _slice_uv(st, sl,
+                               w - (gx + gw), h - (gy + gh), w - (gx),      h - (gy + gh),
+                               w - (gx),      h - gy,        w - (gx + gw), h - gy);
+               }
+          }
+     }
+   
+   num = 0;
+   for (j = 0; j < st->slices_h; j++)
+     {
+        for (i = 0; i < st->slices_w; i++)
+          {
+             _slice_apply(st, st->slices[num], x, y, w, h, ox, oy, ow, oh);
+             _slice_apply(st, st->slices2[num], x, y, w, h, ox, oy, ow, oh);
+             _slice_light(st, st->slices[num], ox, oy, ow, oh);
+             _slice_light(st, st->slices2[num], ox, oy, ow, oh);
+             num++;
+          }
+     }
+   
+   for (i = 0; i <= st->slices_w; i++)
+     {
+        num = i * st->slices_h;
+        for (j = 0; j <= st->slices_h; j++)
+          {
+             Slice *s[4];
+             
+             s[0] = s[1] = s[2] = s[3] = NULL;
+             if ((i > 0)            && (j > 0))
+                s[0] = st->slices[num - 1 - st->slices_h];
+             if ((i < st->slices_w) && (j > 0))
+                s[1] = st->slices[num - 1];
+             if ((i > 0)            && (j < st->slices_h))
+                s[2] = st->slices[num - st->slices_h];
+             if ((i < st->slices_w) && (j < st->slices_h))
+                s[3] = st->slices[num];
+             if (st->dir == 0)
+                _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
+                                            s[2], 1, s[3], 0);
+             else if (st->dir == 1)
+                _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
+                                            s[2], 0, s[3], 1);
+             else if (st->dir == 2)
+                _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
+                                            s[2], 0, s[3], 1);
+             else if (st->dir == 3)
+                _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
+                                            s[2], 1, s[3], 0);
+             s[0] = s[1] = s[2] = s[3] = NULL;
+             if ((i > 0)            && (j > 0))
+                s[0] = st->slices2[num - 1 - st->slices_h];
+             if ((i < st->slices_w) && (j > 0))
+                s[1] = st->slices2[num - 1];
+             if ((i > 0)            && (j < st->slices_h))
+                s[2] = st->slices2[num - st->slices_h];
+             if ((i < st->slices_w) && (j < st->slices_h))
+                s[3] = st->slices2[num];
+             if (st->dir == 0)
+                _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
+                                            s[2], 0, s[3], 1);
+             else if (st->dir == 1)
+                _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
+                                            s[2], 1, s[3], 0);
+             else if (st->dir == 2)
+                _slice_obj_vert_color_merge(s[0], 2, s[1], 3,
+                                            s[2], 1, s[3], 0);
+             else if (st->dir == 3)
+                _slice_obj_vert_color_merge(s[0], 3, s[1], 2,
+                                            s[2], 0, s[3], 1);
+             num++;
+          }
+     }
+   
+   num = 0;
+   for (i = 0; i < st->slices_w; i++)
+     {
+        for (j = 0; j < st->slices_h; j++)
+          {
+             _slice_3d(st, st->slices[num], ox, oy, ow, oh);
+             _slice_3d(st, st->slices2[num], ox, oy, ow, oh);
+             num++;
+          }
+     }
+   
+   return 1;
+}
+
+static void
+_state_end(Widget_Data *st)
+{
+   _state_slices_clear(st);
+}
+
+
 static void
 flip_show_hide(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
    if (elm_flip_front_get(obj))
      {
-        if (wd->front.content)
-          evas_object_show(wd->front.clip);
-        else
-          evas_object_hide(wd->front.clip);
-        if (wd->back.content)
-          evas_object_hide(wd->back.clip);
+        if (wd->pageflip)
+          {
+             if (wd->front.content)
+               {
+                  evas_object_move(wd->front.content, 4999, 4999);
+                  evas_object_show(wd->front.clip);
+               }
+             else
+                evas_object_hide(wd->front.clip);
+             if (wd->back.content)
+                evas_object_show(wd->back.clip);
+             else
+                evas_object_hide(wd->back.clip);
+          }
         else
-          evas_object_hide(wd->back.clip);
+          {
+             if (wd->front.content)
+                evas_object_show(wd->front.clip);
+             else
+                evas_object_hide(wd->front.clip);
+             if (wd->back.content)
+                evas_object_hide(wd->back.clip);
+             else
+                evas_object_hide(wd->back.clip);
+          }
      }
    else
      {
-        if (wd->front.content)
-          evas_object_hide(wd->front.clip);
-        else
-          evas_object_hide(wd->front.clip);
-        if (wd->back.content)
-          evas_object_show(wd->back.clip);
+        if (wd->pageflip)
+          {
+             if (wd->front.content)
+                evas_object_show(wd->front.clip);
+             else
+                evas_object_hide(wd->front.clip);
+             if (wd->back.content)
+               {
+                  evas_object_move(wd->back.content, 4999, 4999);
+                  evas_object_show(wd->back.clip);
+               }
+             else
+                evas_object_hide(wd->back.clip);
+          }
         else
-          evas_object_hide(wd->back.clip);
+          {
+             if (wd->front.content)
+                evas_object_hide(wd->front.clip);
+             else
+                evas_object_hide(wd->front.clip);
+             if (wd->back.content)
+                evas_object_show(wd->back.clip);
+             else
+                evas_object_hide(wd->back.clip);
+          }
      }
 }
 
@@ -197,18 +891,18 @@ _flip_do(Evas_Object *obj, double t, Elm_Flip_Mode mode, int lin, int rev)
    Evas_Coord cx, cy, px, py, foc;
    int lx, ly, lz, lr, lg, lb, lar, lag, lab;
    Widget_Data *wd = elm_widget_data_get(obj);
-
+   
    if (!wd) return;
-
+   
    mf = evas_map_new(4);
    evas_map_smooth_set(mf, 0);
    mb = evas_map_new(4);
    evas_map_smooth_set(mb, 0);
-
+   
    if (wd->front.content)
      {
         const char *type = evas_object_type_get(wd->front.content);
-
+        
         // FIXME: only handles filled obj
         if ((type) && (!strcmp(type, "image")))
           {
@@ -382,6 +1076,14 @@ _flip_do(Evas_Object *obj, double t, Elm_Flip_Mode mode, int lin, int rev)
               evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
            }
          break;
+      case ELM_FLIP_PAGE_LEFT:
+        break;
+      case ELM_FLIP_PAGE_RIGHT:
+        break;
+      case ELM_FLIP_PAGE_UP:
+        break;
+      case ELM_FLIP_PAGE_DOWN:
+        break;
       default:
          break;
      }
@@ -411,21 +1113,112 @@ _flip_do(Evas_Object *obj, double t, Elm_Flip_Mode mode, int lin, int rev)
    evas_map_free(mb);
 }
 
+static void
+_showhide(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   Evas_Coord x, y, w, h;
+   if (!wd) return;
+   
+   evas_object_geometry_get(obj, &x, &y, &w, &h);
+   if (wd->front.content)
+     {
+        if ((wd->pageflip) && (wd->state))
+          {
+             evas_object_move(wd->front.content, 4999, 4999);
+          }
+        else
+          {
+             if (!wd->animator)
+                evas_object_move(wd->front.content, x, y);
+          }
+        evas_object_resize(wd->front.content, w, h);
+     }
+   if (wd->back.content)
+     {
+        if ((wd->pageflip) && (!wd->state))
+          {
+             evas_object_move(wd->back.content, 4999, 4999);
+          }
+        else
+          {
+             if (!wd->animator)
+                evas_object_move(wd->back.content, x, y);
+          }
+        evas_object_resize(wd->back.content, w, h);
+     }
+   
+}
+
 static Eina_Bool
 _flip(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
    double t = ecore_loop_time_get() - wd->start;
+   Evas_Coord w, h;
+   
    if (!wd) return ECORE_CALLBACK_CANCEL;
    if (!wd->animator) return ECORE_CALLBACK_CANCEL;
    
    t = t / wd->len;
    if (t > 1.0) t = 1.0;
    
-   _flip_do(obj, t, wd->mode, 0, 0);
+   evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+   if (wd->mode == ELM_FLIP_PAGE_LEFT)
+     {
+        wd->dir = 0;
+        wd->started = EINA_TRUE;
+        wd->pageflip = EINA_TRUE;
+        wd->down_x = w - 1;
+        wd->down_y = h / 2;
+        wd->x = (1.0 - t) * wd->down_x;
+        wd->y = wd->down_y;
+        flip_show_hide(obj);
+        _state_update(wd);
+     }
+   else if (wd->mode == ELM_FLIP_PAGE_RIGHT)
+     {
+        wd->dir = 1;
+        wd->started = EINA_TRUE;
+        wd->pageflip = EINA_TRUE;
+        wd->down_x = 0;
+        wd->down_y = h / 2;
+        wd->x = (t) * w;
+        wd->y = wd->down_y;
+        flip_show_hide(obj);
+        _state_update(wd);
+     }
+   else if (wd->mode == ELM_FLIP_PAGE_UP)
+     {
+        wd->dir = 2;
+        wd->started = EINA_TRUE;
+        wd->pageflip = EINA_TRUE;
+        wd->down_x = w / 2;
+        wd->down_y = h - 1;
+        wd->x = wd->down_x;
+        wd->y = (1.0 - t) * wd->down_y;
+        flip_show_hide(obj);
+        _state_update(wd);
+     }
+   else if (wd->mode == ELM_FLIP_PAGE_DOWN)
+     {
+        wd->dir = 3;
+        wd->started = EINA_TRUE;
+        wd->pageflip = EINA_TRUE;
+        wd->down_x = w / 2;
+        wd->down_y = 0;
+        wd->x = wd->down_x;
+        wd->y = (t) * h;
+        flip_show_hide(obj);
+        _state_update(wd);
+     }
+   else
+      _flip_do(obj, t, wd->mode, 0, 0);
 
    if (t >= 1.0)
      {
+        wd->pageflip = EINA_FALSE;
+        _state_end(wd);
         evas_object_map_enable_set(wd->front.content, 0);
         evas_object_map_enable_set(wd->back.content, 0);
         // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
@@ -436,6 +1229,7 @@ _flip(Evas_Object *obj)
         wd->animator = NULL;
         wd->state = !wd->state;
         _configure(obj);
+        flip_show_hide(obj);
         evas_object_smart_callback_call(obj, SIG_ANIMATE_DONE, NULL);
         return ECORE_CALLBACK_CANCEL;
      }
@@ -449,45 +1243,36 @@ _configure(Evas_Object *obj)
    Evas_Coord x, y, w, h;
    Evas_Coord fsize;
    if (!wd) return;
+
+   _showhide(obj);
    evas_object_geometry_get(obj, &x, &y, &w, &h);
-   if (wd->front.content)
-     {
-        if (!wd->animator)
-          evas_object_move(wd->front.content, x, y);
-        evas_object_resize(wd->front.content, w, h);
-     }
-   if (wd->back.content)
-     {
-        if (!wd->animator)
-          evas_object_move(wd->back.content, x, y);
-        evas_object_resize(wd->back.content, w, h);
-     }
-   _flip(obj);
+   // FIXME: manual flip wont get fixed
+   if (wd->animator) _flip(obj);
    
    if (wd->event[0])
      {
-        fsize = 16; // FIXME: 16?
+        fsize = (double)w * wd->dir_hitsize[0];
         elm_coords_finger_size_adjust(0, NULL, 1, &fsize);
         evas_object_move(wd->event[0], x, y);
         evas_object_resize(wd->event[0], w, fsize);
      }
    if (wd->event[1])
      {
-        fsize = 16; // FIXME: 16?
+        fsize = (double)w * wd->dir_hitsize[1];
         elm_coords_finger_size_adjust(0, NULL, 1, &fsize);
         evas_object_move(wd->event[1], x, y + h - fsize);
         evas_object_resize(wd->event[1], w, fsize);
      }
    if (wd->event[2])
      {
-        fsize = 16; // FIXME: 16?
+        fsize = (double)h * wd->dir_hitsize[2];
         elm_coords_finger_size_adjust(1, &fsize, 0, NULL);
         evas_object_move(wd->event[2], x, y);
         evas_object_resize(wd->event[2], fsize, h);
      }
    if (wd->event[3])
      {
-        fsize = 16; // FIXME: 16?
+        fsize = (double)h * wd->dir_hitsize[3];
         elm_coords_finger_size_adjust(1, &fsize, 0, NULL);
         evas_object_move(wd->event[3], x + w - fsize, y);
         evas_object_resize(wd->event[3], fsize, h);
@@ -624,15 +1409,17 @@ _event_anim(void *data, double pos)
           }
         break;
       case ELM_FLIP_INTERACTION_PAGE:
-        /*
-         _state_update(st);
-         */
+        wd->pageflip = EINA_TRUE;
+        _configure(data);
+        _state_update(wd);
         break;
       default:
         break;
      }
    if (pos < 1.0) return ECORE_CALLBACK_RENEW;
 
+   wd->pageflip = EINA_FALSE;
+   _state_end(wd);
    evas_object_map_enable_set(wd->front.content, 0);
    evas_object_map_enable_set(wd->back.content, 0);
    // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
@@ -642,6 +1429,7 @@ _event_anim(void *data, double pos)
    // FIXME: end hack
    wd->animator = NULL;
    if (wd->finish) wd->state = !wd->state;
+   flip_show_hide(wd->obj);
    _configure(wd->obj);
    wd->animator = NULL;
    evas_object_smart_callback_call(wd->obj, SIG_ANIMATE_DONE, NULL);
@@ -666,13 +1454,9 @@ _update_job(void *data)
         _flip_do(wd->obj, p, m, 1, rev);
         break;
       case ELM_FLIP_INTERACTION_PAGE:
-        /*   
-         if (_state_update(st))
-         {
-         evas_object_hide(st->front);
-         evas_object_hide(st->back);
-         }
-         */
+        wd->pageflip = EINA_TRUE;
+        _configure(data);
+        _state_update(wd);
         break;
       default:
         break;
@@ -703,7 +1487,6 @@ _down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *even
    wd->h = h;
    wd->down_x = wd->x;
    wd->down_y = wd->y;
-   printf("dn %i %i\n", wd->x, wd->y);
 }
 
 static void
@@ -725,7 +1508,6 @@ _up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_
    wd->h = h;
    wd->ox = wd->x;
    wd->oy = wd->y;
-   printf("up %i %i\n", wd->x, wd->y);
    if (wd->job)
      {
         ecore_job_del(wd->job);
@@ -790,22 +1572,24 @@ _move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *even
              else if ((wd->y > (h / 2)) && (dy <  0) && (abs(dy) >= abs(dx))) wd->dir = 2; // up
              else if ((wd->y < (h / 2)) && (dy >= 0) && (abs(dy) >= abs(dx))) wd->dir = 3; // down
              wd->started = EINA_TRUE;
-             printf("START\n");
+             if (wd->intmode == ELM_FLIP_INTERACTION_PAGE)
+                wd->pageflip = EINA_TRUE;
              flip_show_hide(data);
              evas_smart_objects_calculate(evas_object_evas_get(data));
              _flip(data);
              // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow)
              evas_object_map_enable_set(wd->front.content, 0);
              evas_object_map_enable_set(wd->back.content, 0);
+// FIXME: XXX why does this bork interactive flip??             
 //             evas_object_resize(wd->front.content, 0, 0);
 //             evas_object_resize(wd->back.content, 0, 0);
              evas_smart_objects_calculate(evas_object_evas_get(data));
              _configure(obj);
              // FIXME: end hack
+             evas_object_smart_callback_call(obj, SIG_ANIMATE_BEGIN, NULL);
           }
         else return;
      }
-   printf("mv %i %i\n", wd->x, wd->y);
    if (wd->job) ecore_job_del(wd->job);
    wd->job = ecore_job_add(_update_job, wd);
 }
@@ -1095,17 +1879,8 @@ elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord
  * Runs the flip animation
  *
  * @param obj The flip object
- * @param mode The mode type.  Currently accepted modes are:
+ * @param mode The mode type
  *
- * ELM_FLIP_ROTATE_Y_CENTER_AXIS
- * ELM_FLIP_ROTATE_X_CENTER_AXIS
- * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
- * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
- * ELM_FLIP_CUBE_LEFT
- * ELM_FLIP_CUBE_RIGHT
- * ELM_FLIP_CUBE_UP
- * ELM_FLIP_CUBE_DOWN
- * 
  * @ingroup Flip
  */
 EAPI void
@@ -1118,7 +1893,12 @@ elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
    flip_show_hide(obj);
    wd->mode = mode;
    wd->start = ecore_loop_time_get();
-   wd->len = 0.5;
+   wd->len = 0.5; // FIXME: make config val
+   if ((wd->mode == ELM_FLIP_PAGE_LEFT) ||
+       (wd->mode == ELM_FLIP_PAGE_RIGHT) ||
+       (wd->mode == ELM_FLIP_PAGE_UP) ||
+       (wd->mode == ELM_FLIP_PAGE_DOWN))
+      wd->pageflip = EINA_TRUE;
    // force calc to contents are the right size before transition
    evas_smart_objects_calculate(evas_object_evas_get(obj));
    _flip(obj);
@@ -1130,18 +1910,73 @@ elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
    evas_smart_objects_calculate(evas_object_evas_get(obj));
    _configure(obj);
    // FIXME: end hack
+   evas_object_smart_callback_call(obj, SIG_ANIMATE_BEGIN, NULL);
 }
 
+/**
+ * Set the interactive flip mode
+ * 
+ * @param obj The flip object
+ * @param mode The interactive flip mode to use
+ * 
+ * This sets if the flip should be interactive (allow user to click and
+ * drag a side of the flip to reveal the back page and cause it to flip).
+ * By default a flip is not interactive. You may also need to set which
+ * sides of the flip are "active" for flipping and how much space they use
+ * (a minimum of a finger size) with elm_flip_interacton_direction_enabled_set()
+ * and elm_flip_interacton_direction_hitsize_set()
+ * 
+ * @ingroup Flip
+ */
 EAPI void
 elm_flip_interaction_set(Evas_Object *obj, Elm_Flip_Interaction mode)
 {
    ELM_CHECK_WIDTYPE(obj, widtype);
+   int i;
    Widget_Data *wd = elm_widget_data_get(obj);
    if (!wd) return;
    if (wd->intmode == mode) return;
    wd->intmode = mode;
+   for (i = 0; i < 4; i++)
+     {
+        if (wd->intmode == ELM_FLIP_INTERACTION_NONE)
+          {
+             if (wd->event[i])
+               {
+                  evas_object_del(wd->event[i]);
+                  wd->event[i] = NULL;
+               }
+          }
+        else
+          {
+             if ((wd->dir_enabled[i]) && (!wd->event[i]))
+               {
+                  wd->event[i] = evas_object_rectangle_add(evas_object_evas_get(obj));
+                  elm_widget_sub_object_add(obj, wd->event[i]);
+                  evas_object_clip_set(wd->event[i], evas_object_clip_get(obj));
+                  evas_object_color_set(wd->event[i], 0, 0, 0, 0);
+                  evas_object_show(wd->event[i]);
+                  evas_object_smart_member_add(wd->event[i], obj);
+                  evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_DOWN, _down_cb, obj);
+                  evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_UP, _up_cb, obj);
+                  evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_MOVE, _move_cb, obj);
+               }
+          }
+     }
+   _sizing_eval(obj);
+   _configure(obj);
 }
 
+/**
+ * Get the interactive flip mode
+ * 
+ * @param obj The flip object
+ * @return The interactive flip mode
+ * 
+ * Returns the interactive flip mode set by elm_flip_interaction_set()
+ * 
+ * @ingroup Flip
+ */
 EAPI Elm_Flip_Interaction
 elm_flip_interaction_get(const Evas_Object *obj)
 {
@@ -1151,6 +1986,18 @@ elm_flip_interaction_get(const Evas_Object *obj)
    return wd->intmode;
 }
 
+/**
+ * Set which directions of the flip respond to interactive flip
+ * 
+ * @param obj The flip object
+ * @param dir The direction to change
+ * @param enabled If that direction is enabled or not
+ * 
+ * By default all directions are disabled, so you may want to enable the
+ * desired directions for flipping if you need interactive flipping.
+ * 
+ * @ingroup Flip
+ */
 EAPI void
 elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction dir, Eina_Bool enabled)
 {
@@ -1166,7 +2013,8 @@ elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction d
    if (i < 0) return;
    if (wd->dir_enabled[i] == enabled) return;
    wd->dir_enabled[i] = enabled;
-   if (wd->dir_enabled[i]) 
+   if (wd->intmode == ELM_FLIP_INTERACTION_NONE) return;
+   if ((wd->dir_enabled[i]) && (!wd->event[i]))
      {
         wd->event[i] = evas_object_rectangle_add(evas_object_evas_get(obj));
         elm_widget_sub_object_add(obj, wd->event[i]);
@@ -1178,14 +2026,26 @@ elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction d
         evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_UP, _up_cb, obj);
         evas_object_event_callback_add(wd->event[i], EVAS_CALLBACK_MOUSE_MOVE, _move_cb, obj);
      }
-   else
+   else if (!(wd->dir_enabled[i]) && (wd->event[i]))
      {
         evas_object_del(wd->event[i]);
         wd->event[i] = NULL;
      }
    _sizing_eval(obj);
+   _configure(obj);
 }
 
+/**
+ * Get the enabled state of that flip direction
+ * 
+ * @param obj The flip object
+ * @param dir The direction to check
+ * @return If that direction is enabled or not
+ * 
+ * Gets the enabled state set by elm_flip_interacton_direction_enabled_set()
+ * 
+ * @ingroup Flip
+ */
 EAPI Eina_Bool
 elm_flip_interacton_direction_enabled_get(Evas_Object *obj, Elm_Flip_Direction dir)
 {
@@ -1200,3 +2060,58 @@ elm_flip_interacton_direction_enabled_get(Evas_Object *obj, Elm_Flip_Direction d
    if (i < 0) return EINA_FALSE;
    return wd->dir_enabled[i];
 }
+
+/**
+ * Set the amount of the flip that is sensitive to interactive flip
+ * 
+ * @param obj The flip object
+ * @param dir The direction to modify
+ * @param hitsize The amount of that dimension (0.0 to 1.0) to use
+ * 
+ * @ingroup Flip
+ */
+EAPI void
+elm_flip_interacton_direction_hitsize_set(Evas_Object *obj, Elm_Flip_Direction dir, double hitsize)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   int i = -1;
+   if (!wd) return;
+   if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
+   else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
+   else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
+   else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
+   if (i < 0) return;
+   if (hitsize < 0.0) hitsize = 0.0;
+   else if (hitsize > 1.0) hitsize = 1.0;
+   if (wd->dir_hitsize[i] == hitsize) return;
+   wd->dir_hitsize[i] = hitsize;
+   _sizing_eval(obj);
+   _configure(obj);
+}
+
+/**
+ * Get the amount of the flip that is sensitive to interactive flip
+ * 
+ * @param obj The flip object
+ * @param dir The direction to check
+ * @return The size set for that direction
+ * 
+ * Returns the amount os sensitive area set by elm_flip_interacton_direction_hitsize_set().
+ * 
+ * @ingroup Flip
+ */
+EAPI double
+elm_flip_interacton_direction_hitsize_get(Evas_Object *obj, Elm_Flip_Direction dir)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   Widget_Data *wd = elm_widget_data_get(obj);
+   int i = -1;
+   if (!wd) return 0.0;
+   if      (dir == ELM_FLIP_DIRECTION_UP)    i = 0;
+   else if (dir == ELM_FLIP_DIRECTION_DOWN)  i = 1;
+   else if (dir == ELM_FLIP_DIRECTION_LEFT)  i = 2;
+   else if (dir == ELM_FLIP_DIRECTION_RIGHT) i = 3;
+   if (i < 0) return 0.0;
+   return wd->dir_hitsize[i];
+}