flip now supports the beginnings of interactive mode. - drag to flip
authorCarsten Haitzler <raster@rasterman.com>
Wed, 25 May 2011 06:06:48 +0000 (06:06 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Wed, 25 May 2011 06:06:48 +0000 (06:06 +0000)
it in a direction.

SVN revision: 59660

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

index 43f4d10..4c96bf7 100644 (file)
@@ -100,6 +100,7 @@ void test_weather(void *data, Evas_Object *obj, void *event_info);
 void test_flip(void *data, Evas_Object *obj, void *event_info);
 void test_flip2(void *data, Evas_Object *obj, void *event_info);
 void test_flip3(void *data, Evas_Object *obj, void *event_info);
+void test_flip4(void *data, Evas_Object *obj, void *event_info);
 void test_flip_page(void *data, Evas_Object *obj, void *event_info);
 void test_label(void *data, Evas_Object *obj, void *event_info);
 void test_conformant(void *data, Evas_Object *obj, void *event_info);
@@ -357,6 +358,7 @@ my_win_main(char *autorun)
    ADD_TEST("Flip", test_flip);
    ADD_TEST("Flip 2", test_flip2);
    ADD_TEST("Flip 3", test_flip3);
+   ADD_TEST("Flip Interactive", test_flip4);
    ADD_TEST("Flip Page", test_flip_page);
    ADD_TEST("Label", test_label);
    ADD_TEST("Conformant", test_conformant);
index bb56a41..731bbd2 100644 (file)
@@ -378,7 +378,7 @@ test_flip3(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    Evas_Object *win, *bg, *bx, *bx2, *fl, *fl_f, *fl_b, *o, *bt, *fr;
    char buf[PATH_MAX];
 
-   win = elm_win_add(NULL, "flip flip", ELM_WIN_BASIC);
+   win = elm_win_add(NULL, "flip3", ELM_WIN_BASIC);
    elm_win_title_set(win, "Flip Flip");
    elm_win_autodel_set(win, 1);
 
@@ -491,4 +491,73 @@ test_flip3(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    evas_object_resize(win, 320, 480);
    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);
+}
+
+void
+test_flip4(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Evas_Object *win, *bg, *bx, *fl, *im, *li, *bt;
+   char buf[PATH_MAX];
+
+   win = elm_win_add(NULL, "flip4", ELM_WIN_BASIC);
+   elm_win_title_set(win, "Flip Interactive");
+   elm_win_autodel_set(win, 1);
+
+   bg = elm_bg_add(win);
+   elm_win_resize_object_add(win, bg);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_show(bg);
+
+   bx = elm_box_add(win);
+   evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bx);
+   evas_object_show(bx);
+
+   fl = elm_flip_add(win);
+   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);
+   
+   elm_flip_interaction_set(fl, ELM_FLIP_INTERACTION_CUBE);
+   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);
+   evas_object_show(fl);
+
+   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, "twofish.jpg");
+   evas_object_image_file_set(im, buf, NULL);
+   elm_flip_content_front_set(fl, im);
+   evas_object_show(im);
+   
+   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);
+   elm_list_item_append(li, "Item 1", NULL, NULL, NULL, NULL);
+   elm_list_item_append(li, "Item 2", NULL, NULL, NULL, NULL);
+   elm_list_item_append(li, "Item 3 (Which is very long just for testing purposes)", NULL, NULL, NULL, NULL);
+   elm_list_go(li);
+   elm_flip_content_back_set(fl, li);
+   evas_object_show(li);
+   
+   bt = elm_button_add(win);
+   elm_button_label_set(bt, "Go");
+   evas_object_smart_callback_add(bt, "clicked", my_fl_go, fl);
+   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);
+   evas_object_show(bt);
+   
+   evas_object_resize(win, 320, 480);
+   evas_object_show(win);
+}
 #endif
index 199c22e..7b6c73b 100644 (file)
@@ -2494,6 +2494,20 @@ extern "C" {
         ELM_FLIP_CUBE_UP,
         ELM_FLIP_CUBE_DOWN
      } Elm_Flip_Mode;
+   typedef enum _Elm_Flip_Interaction
+     {
+        ELM_FLIP_INTERACTION_NONE,
+        ELM_FLIP_INTERACTION_ROTATE,
+        ELM_FLIP_INTERACTION_CUBE,
+        ELM_FLIP_INTERACTION_PAGE
+     } Elm_Flip_Interaction;
+   typedef enum _Elm_Flip_Direction
+     {
+        ELM_FLIP_DIRECTION_UP,
+        ELM_FLIP_DIRECTION_DOWN,
+        ELM_FLIP_DIRECTION_LEFT,
+        ELM_FLIP_DIRECTION_RIGHT
+     } Elm_Flip_Direction;
 
    EAPI Evas_Object *elm_flip_add(Evas_Object *parent) EINA_ARG_NONNULL(1);
    EAPI void         elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content) EINA_ARG_NONNULL(1);
@@ -2505,6 +2519,10 @@ extern "C" {
    EAPI Eina_Bool    elm_flip_front_get(const Evas_Object *obj) EINA_ARG_NONNULL(1);
    EAPI void         elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc, Evas_Coord x, Evas_Coord y) EINA_ARG_NONNULL(1);
    EAPI void         elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode) EINA_ARG_NONNULL(1);
+   EAPI void         elm_flip_interaction_set(Evas_Object *obj, Elm_Flip_Interaction mode);
+   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);
    /* smart callbacks called:
     * "animate,done" - when a flip animation is finished
     */
index 176861e..2ccbd9d 100644 (file)
@@ -26,14 +26,24 @@ typedef struct _Widget_Data Widget_Data;
 
 struct _Widget_Data
 {
+   Evas_Object *obj;
    Ecore_Animator *animator;
    double start, len;
    Elm_Flip_Mode mode;
    Evas_Object *clip;
+   Evas_Object *event[4];
    struct {
-        Evas_Object *content, *clip;
+      Evas_Object *content, *clip;
    } front, back;
+   Ecore_Job *job;
+   Evas_Coord down_x, down_y, x, y, ox, oy, w, h;
+   Elm_Flip_Interaction intmode;
+   int dir;
+   Eina_Bool dir_enabled[4];
    Eina_Bool state : 1;
+   Eina_Bool down : 1;
+   Eina_Bool finish : 1;
+   Eina_Bool started : 1;
 };
 
 static const char *widtype = NULL;
@@ -91,6 +101,7 @@ _sizing_eval(Evas_Object *obj)
    Widget_Data *wd = elm_widget_data_get(obj);
    Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
    Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
+   int fingx = 0, fingy = 0;
    if (!wd) return;
    if (wd->front.content)
      evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
@@ -106,6 +117,13 @@ _sizing_eval(Evas_Object *obj)
    if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
    if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
 
+   if (wd->dir_enabled[0]) fingy++;
+   if (wd->dir_enabled[1]) fingy++;
+   if (wd->dir_enabled[2]) fingx++;
+   if (wd->dir_enabled[3]) fingx++;
+   
+   elm_coords_finger_size_adjust(fingx, &minw, fingy, &minh);
+   
    evas_object_size_hint_min_set(obj, minw, minh);
    evas_object_size_hint_max_set(obj, maxw, maxh);
 }
@@ -170,21 +188,17 @@ flip_show_hide(Evas_Object *obj)
      }
 }
 
-static Eina_Bool
-_flip(Evas_Object *obj)
+static void
+_flip_do(Evas_Object *obj, double t, Elm_Flip_Mode mode, int lin, int rev)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   double t = ecore_loop_time_get() - wd->start;
    Evas_Coord x, y, w, h;
-   double p, deg;
+   double p, deg, pp;
    Evas_Map *mf, *mb;
    Evas_Coord cx, cy, px, py, foc;
    int lx, ly, lz, lr, lg, lb, lar, lag, lab;
-   if (!wd->animator) return ECORE_CALLBACK_CANCEL;
-   t = t / wd->len;
-   if (t > 1.0) t = 1.0;
+   Widget_Data *wd = elm_widget_data_get(obj);
 
-   if (!wd) return ECORE_CALLBACK_CANCEL;
+   if (!wd) return;
 
    mf = evas_map_new(4);
    evas_map_smooth_set(mf, 0);
@@ -193,13 +207,46 @@ _flip(Evas_Object *obj)
 
    if (wd->front.content)
      {
-        evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
-        evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
+        const char *type = evas_object_type_get(wd->front.content);
+
+        // FIXME: only handles filled obj
+        if ((type) && (!strcmp(type, "image")))
+          {
+             int iw, ih;
+             evas_object_image_size_get(wd->front.content, &iw, &ih);
+             evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
+             evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
+             evas_map_point_image_uv_set(mf, 0, 0, 0);
+             evas_map_point_image_uv_set(mf, 1, iw, 0);
+             evas_map_point_image_uv_set(mf, 2, iw, ih);
+             evas_map_point_image_uv_set(mf, 3, 0, ih);
+          }
+        else
+          {
+             evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
+             evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
+          }
      }
    if (wd->back.content)
      {
-        evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
-        evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
+        const char *type = evas_object_type_get(wd->back.content);
+        
+        if ((type) && (!strcmp(type, "image")))
+          {
+             int iw, ih;
+             evas_object_image_size_get(wd->back.content, &iw, &ih);
+             evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
+             evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
+             evas_map_point_image_uv_set(mb, 0, 0, 0);
+             evas_map_point_image_uv_set(mb, 1, iw, 0);
+             evas_map_point_image_uv_set(mb, 2, iw, ih);
+             evas_map_point_image_uv_set(mb, 3, 0, ih);
+          }
+        else
+          {
+             evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
+             evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
+          }
      }
 
    evas_object_geometry_get(obj, &x, &y, &w, &h);
@@ -221,43 +268,57 @@ _flip(Evas_Object *obj)
    lag = 0;
    lab = 0;
 
-   switch (wd->mode)
+   switch (mode)
      {
       case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          if (wd->state) deg = 180.0 * p;
          else deg = 180 + (180.0 * p);
+         if (rev) deg = -deg;
          evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
-         evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
+         evas_map_util_3d_rotate(mb, 0.0, 180 + deg, 0.0, cx, cy, 0);
          break;
       case ELM_FLIP_ROTATE_X_CENTER_AXIS:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          if (wd->state) deg = 180.0 * p;
          else deg = 180 + (180.0 * p);
+         if (rev) deg = -deg;
          evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
-         evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
+         evas_map_util_3d_rotate(mb, 180.0 + deg, 0.0, 0.0, cx, cy, 0);
          break;
       case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          if (wd->state) deg = 180.0 * p;
          else deg = 180 + (180.0 * p);
+         if (rev) deg = -deg;
          evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
-         evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
+         evas_map_util_3d_rotate(mb, 180 + deg, 0.0, 180 + deg, cx, cy, 0);
          break;
       case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          if (wd->state) deg = 180.0 * p;
          else deg = 180 + (180.0 * p);
+         if (rev) deg = -deg;
          evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
-         evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
+         evas_map_util_3d_rotate(mb, 0.0, 180.0 + deg, 180.0 + deg, cx, cy, 0);
          break;
       case ELM_FLIP_CUBE_LEFT:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          deg = -90.0 * p;
          if (wd->state)
            {
@@ -272,7 +333,9 @@ _flip(Evas_Object *obj)
          break;
       case ELM_FLIP_CUBE_RIGHT:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          deg = 90.0 * p;
          if (wd->state)
            {
@@ -287,7 +350,9 @@ _flip(Evas_Object *obj)
          break;
       case ELM_FLIP_CUBE_UP:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          deg = -90.0 * p;
          if (wd->state)
            {
@@ -302,7 +367,9 @@ _flip(Evas_Object *obj)
          break;
       case ELM_FLIP_CUBE_DOWN:
          p = 1.0 - t;
-         p = 1.0 - (p * p);
+         pp = p;
+         if (!lin) pp = (p * p);
+         p = 1.0 - pp;
          deg = 90.0 * p;
          if (wd->state)
            {
@@ -342,6 +409,20 @@ _flip(Evas_Object *obj)
 
    evas_map_free(mf);
    evas_map_free(mb);
+}
+
+static Eina_Bool
+_flip(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   double t = ecore_loop_time_get() - wd->start;
+   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);
 
    if (t >= 1.0)
      {
@@ -366,6 +447,7 @@ _configure(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
    Evas_Coord x, y, w, h;
+   Evas_Coord fsize;
    if (!wd) return;
    evas_object_geometry_get(obj, &x, &y, &w, &h);
    if (wd->front.content)
@@ -381,6 +463,35 @@ _configure(Evas_Object *obj)
         evas_object_resize(wd->back.content, w, h);
      }
    _flip(obj);
+   
+   if (wd->event[0])
+     {
+        fsize = 16; // FIXME: 16?
+        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?
+        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?
+        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?
+        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);
+     }
 }
 
 static void
@@ -401,6 +512,304 @@ _animate(void *data)
    return _flip(data);
 }
 
+static double
+_pos_get(Widget_Data *wd, int *rev, Elm_Flip_Mode *m)
+{
+   Evas_Coord x, y, w, h;
+   double t = 1.0;
+   
+   evas_object_geometry_get(wd->obj, &x, &y, &w, &h);
+   switch (wd->intmode)
+     {
+      case ELM_FLIP_INTERACTION_ROTATE:
+      case ELM_FLIP_INTERACTION_CUBE:
+          {
+             if (wd->dir == 0)
+               {
+                  if (wd->down_x > 0)
+                     t = 1.0 - ((double)wd->x / (double)wd->down_x);
+                  *rev = 1;
+               }
+             else if (wd->dir == 1)
+               {
+                  if (wd->down_x < w)
+                     t = 1.0 - ((double)(w - wd->x) / (double)(w - wd->down_x));
+               }
+             else if (wd->dir == 2)
+               {
+                  if (wd->down_y > 0)
+                     t = 1.0 - ((double)wd->y / (double)wd->down_y);
+               }
+             else if (wd->dir == 3)
+               {
+                  if (wd->down_y < h)
+                     t = 1.0 - ((double)(h - wd->y) / (double)(h - wd->down_y));
+                  *rev = 1;
+               }
+             
+             if (t < 0.0) t = 0.0;
+             else if (t > 1.0) t = 1.0;
+             
+             if ((wd->dir == 0) || (wd->dir == 1))
+               {
+                  if (wd->intmode == ELM_FLIP_INTERACTION_ROTATE) 
+                     *m = ELM_FLIP_ROTATE_Y_CENTER_AXIS;
+                  else if (wd->intmode == ELM_FLIP_INTERACTION_CUBE)
+                    {
+                       if (*rev)
+                          *m = ELM_FLIP_CUBE_LEFT;
+                       else
+                          *m = ELM_FLIP_CUBE_RIGHT;
+                    }
+               }
+             else
+               {
+                  if (wd->intmode == ELM_FLIP_INTERACTION_ROTATE) 
+                     *m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
+                  else if (wd->intmode == ELM_FLIP_INTERACTION_CUBE)
+                    {
+                       if (*rev)
+                          *m = ELM_FLIP_CUBE_UP;
+                       else
+                          *m = ELM_FLIP_CUBE_DOWN;
+                    }
+               }
+          }
+      default:
+        break;
+     }
+   return t;
+}
+
+static Eina_Bool
+_event_anim(void *data, double pos)
+{
+   Widget_Data *wd = data;
+   double p;
+   
+   p = ecore_animator_pos_map(pos, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
+   if (wd->finish)
+     {
+        if (wd->dir == 0)
+           wd->x = wd->ox * (1.0 - p);
+        else if (wd->dir == 1)
+           wd->x = wd->ox + ((wd->w - wd->ox) * p);
+        else if (wd->dir == 2)
+           wd->y = wd->oy * (1.0 - p);
+        else if (wd->dir == 3)
+           wd->y = wd->oy + ((wd->h - wd->oy) * p);
+     }
+   else
+     {
+        if (wd->dir == 0)
+           wd->x = wd->ox + ((wd->w - wd->ox) * p);
+        else if (wd->dir == 1)
+           wd->x = wd->ox * (1.0 - p);
+        else if (wd->dir == 2)
+           wd->y = wd->oy + ((wd->h - wd->oy) * p);
+        else if (wd->dir == 3)
+           wd->y = wd->oy * (1.0 - p);
+     }
+   switch (wd->intmode)
+     {
+      case ELM_FLIP_INTERACTION_NONE:
+        break;
+      case ELM_FLIP_INTERACTION_ROTATE:
+      case ELM_FLIP_INTERACTION_CUBE:
+          {
+             Elm_Flip_Mode m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
+             int rev = 0;
+             p = _pos_get(wd, &rev, &m);
+             _flip_do(wd->obj, p, m, 1, rev);
+          }
+        break;
+      case ELM_FLIP_INTERACTION_PAGE:
+        /*
+         _state_update(st);
+         */
+        break;
+      default:
+        break;
+     }
+   if (pos < 1.0) return ECORE_CALLBACK_RENEW;
+
+   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
+   evas_object_resize(wd->front.content, 0, 0);
+   evas_object_resize(wd->back.content, 0, 0);
+   evas_smart_objects_calculate(evas_object_evas_get(wd->obj));
+   // FIXME: end hack
+   wd->animator = NULL;
+   if (wd->finish) wd->state = !wd->state;
+   _configure(wd->obj);
+   wd->animator = NULL;
+   evas_object_smart_callback_call(wd->obj, SIG_ANIMATE_DONE, NULL);
+   
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_update_job(void *data)
+{
+   Widget_Data *wd = data;
+   double p;
+   Elm_Flip_Mode m = ELM_FLIP_ROTATE_X_CENTER_AXIS;
+   int rev = 0;
+   
+   wd->job = NULL;
+   switch (wd->intmode)
+     {
+      case ELM_FLIP_INTERACTION_ROTATE:
+      case ELM_FLIP_INTERACTION_CUBE:
+        p = _pos_get(wd, &rev, &m);
+        _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);
+         }
+         */
+        break;
+      default:
+        break;
+     }
+}
+
+static void
+_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Evas_Object *fl = data;
+   Widget_Data *wd = elm_widget_data_get(fl);
+   Evas_Event_Mouse_Down *ev = event_info;
+   Evas_Coord x, y, w, h;
+   
+   if (!wd) return;
+   if (ev->button != 1) return;
+   if (wd->animator)
+     {
+        ecore_animator_del(wd->animator);
+        wd->animator = NULL;
+     }
+   wd->down = EINA_TRUE;
+   wd->started = EINA_FALSE;
+   evas_object_geometry_get(data, &x, &y, &w, &h);
+   wd->x = ev->canvas.x - x;
+   wd->y = ev->canvas.y - y;
+   wd->w = w;                
+   wd->h = h;
+   wd->down_x = wd->x;
+   wd->down_y = wd->y;
+   printf("dn %i %i\n", wd->x, wd->y);
+}
+
+static void
+_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Evas_Object *fl = data;
+   Widget_Data *wd = elm_widget_data_get(fl);
+   Evas_Event_Mouse_Up *ev = event_info;
+   Evas_Coord x, y, w, h;
+   double tm = 0.5;
+   
+   if (!wd) return;
+   if (ev->button != 1) return;
+   wd->down = 0;
+   evas_object_geometry_get(data, &x, &y, &w, &h);
+   wd->x = ev->canvas.x - x;
+   wd->y = ev->canvas.y - y;
+   wd->w = w;
+   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);
+        wd->job = NULL;
+     }
+   wd->finish = EINA_FALSE;
+   if (wd->dir == 0)
+     {
+        tm = (double)wd->x / (double)wd->w;
+        if (wd->x < (wd->w / 2)) wd->finish = EINA_TRUE;
+     }
+   else if (wd->dir == 1)
+     {
+        if (wd->x > (wd->w / 2)) wd->finish = EINA_TRUE;
+        tm = 1.0 - ((double)wd->x / (double)wd->w);
+     }
+   else if (wd->dir == 2)
+     {
+        if (wd->y < (wd->h / 2)) wd->finish = EINA_TRUE;
+        tm = (double)wd->y / (double)wd->h;
+     }
+   else if (wd->dir == 3)
+     {
+        if (wd->y > (wd->h / 2)) wd->finish = EINA_TRUE;
+        tm = 1.0 - ((double)wd->y / (double)wd->h);
+     }
+   if (tm < 0.01) tm = 0.01;
+   else if (tm > 0.99) tm = 0.99;
+   if (!wd->finish) tm = 1.0 - tm;
+   tm *= 1.0; // FIXME: config for anim time
+   if (wd->animator) ecore_animator_del(wd->animator);
+   wd->animator = ecore_animator_timeline_add(tm, _event_anim, wd);
+   _event_anim(wd, 0.0);
+}
+
+static void
+_move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Evas_Object *fl = data;
+   Widget_Data *wd = elm_widget_data_get(fl);
+   Evas_Event_Mouse_Move *ev = event_info;
+   Evas_Coord x, y, w, h;
+   
+   if (!wd) return;
+   if (!wd->down) return;
+   evas_object_geometry_get(data, &x, &y, &w, &h);
+   wd->x = ev->cur.canvas.x - x;
+   wd->y = ev->cur.canvas.y - y;
+   wd->w = w;                
+   wd->h = h;
+   if (!wd->started)
+     {
+        Evas_Coord dx, dy;
+        
+        dx = wd->x - wd->down_x;
+        dy = wd->y - wd->down_y;
+        if (((dx * dx) + (dy * dy)) > (_elm_config->finger_size * _elm_config->finger_size / 4))
+          {
+             wd->dir = 0;
+             if      ((wd->x > (w / 2)) && (dx <  0) && (abs(dx) >  abs(dy))) wd->dir = 0; // left
+             else if ((wd->x < (w / 2)) && (dx >= 0) && (abs(dx) >  abs(dy))) wd->dir = 1; // right
+             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");
+             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);
+//             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
+          }
+        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);
+}
+
 /**
  * Add a new flip to the parent
  *
@@ -415,7 +824,7 @@ elm_flip_add(Evas_Object *parent)
    Evas_Object *obj;
    Evas *e;
    Widget_Data *wd;
-
+   
    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
 
    ELM_SET_WIDTYPE(widtype, "flip");
@@ -427,6 +836,8 @@ elm_flip_add(Evas_Object *parent)
    elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
    elm_widget_can_focus_set(obj, EINA_FALSE);
 
+   wd->obj = obj;
+   
    wd->clip = evas_object_rectangle_add(e);
    evas_object_static_clip_set(wd->clip, 1);
    evas_object_color_set(wd->clip, 255, 255, 255, 255);
@@ -463,7 +874,8 @@ elm_flip_add(Evas_Object *parent)
    evas_object_smart_callbacks_descriptions_set(obj, _signals);
 
    wd->state = 1;
-
+   wd->intmode = ELM_FLIP_INTERACTION_NONE;
+   
    _sizing_eval(obj);
 
    return obj;
@@ -486,6 +898,7 @@ elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
 {
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   int i;
    if (!wd) return;
    if (wd->front.content == content) return;
    if (wd->front.content) evas_object_del(wd->back.content);
@@ -504,6 +917,10 @@ elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
    evas_smart_objects_calculate(evas_object_evas_get(obj));
    flip_show_hide(obj);
    _configure(obj);
+   if (wd->intmode != ELM_FLIP_INTERACTION_NONE)
+     {
+        for (i = 0; i < 4; i++) evas_object_raise(wd->event[i]);
+     }
 }
 
 /**
@@ -523,6 +940,7 @@ elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
 {
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   int i;
    if (!wd) return;
    if (wd->back.content == content) return;
    if (wd->back.content) evas_object_del(wd->back.content);
@@ -541,6 +959,10 @@ elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
    evas_smart_objects_calculate(evas_object_evas_get(obj));
    flip_show_hide(obj);
    _configure(obj);
+   if (wd->intmode != ELM_FLIP_INTERACTION_NONE)
+     {
+        for (i = 0; i < 4; i++) evas_object_raise(wd->event[i]);
+     }
 }
 
 /**
@@ -667,6 +1089,8 @@ elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord
    if (!wd) return;
 }
 
+// FIXME: add ambient and lighting control
+
 /**
  * Runs the flip animation
  *
@@ -682,9 +1106,6 @@ elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord
  * ELM_FLIP_CUBE_UP
  * ELM_FLIP_CUBE_DOWN
  * 
- * FIXME: add - ELM_FLIP_CUBE_UP
- * FIXME: add - ELM_FLIP_CUBE_DOWN
- *
  * @ingroup Flip
  */
 EAPI void
@@ -710,3 +1131,72 @@ elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
    _configure(obj);
    // FIXME: end hack
 }
+
+EAPI void
+elm_flip_interaction_set(Evas_Object *obj, Elm_Flip_Interaction mode)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+   if (wd->intmode == mode) return;
+   wd->intmode = mode;
+}
+
+EAPI Elm_Flip_Interaction
+elm_flip_interaction_get(const Evas_Object *obj)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) ELM_FLIP_INTERACTION_NONE;
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return ELM_FLIP_INTERACTION_NONE;
+   return wd->intmode;
+}
+
+EAPI void
+elm_flip_interacton_direction_enabled_set(Evas_Object *obj, Elm_Flip_Direction dir, Eina_Bool enabled)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   int i = -1;
+   if (!wd) return;
+   enabled = !!enabled;
+   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 (wd->dir_enabled[i] == enabled) return;
+   wd->dir_enabled[i] = enabled;
+   if (wd->dir_enabled[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);
+     }
+   else
+     {
+        evas_object_del(wd->event[i]);
+        wd->event[i] = NULL;
+     }
+   _sizing_eval(obj);
+}
+
+EAPI Eina_Bool
+elm_flip_interacton_direction_enabled_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 EINA_FALSE;
+   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 EINA_FALSE;
+   return wd->dir_enabled[i];
+}