#include "ephoto.h"

typedef struct _Ephoto_Cropper Ephoto_Cropper;
struct _Ephoto_Cropper
{
   Evas_Object *main;
   Evas_Object *parent;
   Evas_Object *image_parent;
   Evas_Object *box;
   Evas_Object *editor;
   Evas_Object *image;
   Evas_Object *cropper;
   Evas_Object *layout;
   Evas_Object *cropw;
   Evas_Object *croph;
   Eina_List   *handlers;
   Evas_Coord   startx;
   Evas_Coord   starty;
   Evas_Coord   offsetx;
   Evas_Coord   offsety;
   Eina_Bool    resizing;
};

static void
_calculate_cropper_size(void *data, Evas_Object *obj EINA_UNUSED,
                        const char *emission EINA_UNUSED,
                        const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;
   Evas_Coord w, h, cw, ch, iw, ih, nw, nh;
   double scalew, scaleh;

   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.image", 0, 0, &w, &h);
   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.cropper", 0, 0, &cw, &ch);
   evas_object_image_size_get(ec->image, &iw, &ih);

   scalew = (double)cw / (double)w;
   scaleh = (double)ch / (double)h;

   nw = iw * scalew;
   nh = ih * scaleh;

   elm_slider_value_set(ec->cropw, nw);
   elm_slider_value_set(ec->croph, nh);

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   msg->val[0] = 11;
   msg->val[1] = nw;
   msg->val[2] = nh;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static void
_cropper_changed_width(void *data, Evas_Object *obj EINA_UNUSED,
                       void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msgl, *msgr;
   Evas_Coord mw, cx, cw, nw, lx, lw, iw, left, right;
   double scalew;

   mw = elm_slider_value_get(ec->cropw);

   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.image", &lx, 0, &lw, 0);
   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.cropper", &cx, 0, &cw, 0);
   evas_object_image_size_get(ec->image, &iw, 0);
   scalew = (double)mw / (double)iw;

   nw = lw * scalew;
   left = (nw - cw) / 2;
   right = (nw - cw) / 2;

   if ((cx + cw + right) >= (lx + lw))
     {
        right = (lx + lw) - (cx + cw);
        left += left - right;
     }
   else if ((cx - left) <= lx)
     {
        left = cx - lx;
        right += right - left;
     }
   left *= -1;

   msgl = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msgl->count = 3;
   msgl->val[0] = 8;
   msgl->val[1] = left;
   msgl->val[2] = 0;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msgl);

   msgr = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msgr->count = 3;
   msgr->val[0] = 4;
   msgr->val[1] = right;
   msgr->val[2] = 0;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msgr);
}

static void
_cropper_changed_height(void *data, Evas_Object *obj EINA_UNUSED,
                        void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msgt, *msgb;
   Evas_Coord mh, ch, cy, nh, lh, ly, ih, top, bottom;
   double scaleh;

   mh = elm_slider_value_get(ec->croph);

   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.image", 0, &ly, 0, &lh);
   edje_object_part_geometry_get(elm_layout_edje_get(ec->layout),
                                 "ephoto.swallow.cropper", 0, &cy, 0, &ch);
   evas_object_image_size_get(ec->image, 0, &ih);

   scaleh = (double)mh / (double)ih;
   nh = lh * scaleh;
   top = (nh - ch) / 2;
   bottom = (nh - ch) / 2;

   if ((cy + ch + bottom) >= (ly + lh))
     {
        bottom = (ly + lh) - (cy + ch);
        top += top - bottom;
     }
   else if ((cy - top) <= ly)
     {
        top = cy - ly;
        bottom += bottom - top;
     }
   top *= -1;

   msgt = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msgt->count = 3;
   msgt->val[0] = 2;
   msgt->val[1] = 0;
   msgt->val[2] = top;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msgt);

   msgb = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msgb->count = 3;
   msgb->val[0] = 6;
   msgb->val[1] = 0;
   msgb->val[2] = bottom;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msgb);
}

static void
_reset_crop(void *data, Evas_Object *obj EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   msg->val[0] = 10;
   msg->val[1] = 0;
   msg->val[2] = 0;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static void
_apply_crop(void *data, Evas_Object *obj EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Evas_Object *edje = elm_layout_edje_get(ec->layout);

   Evas_Coord x, y, w, h, cx, cy, cw, ch, iw, ih;
   Evas_Coord nx, ny, nw, nh, i, j, tmpx, tmpy, ind, index;
   double scalex, scaley, scalew, scaleh;
   unsigned int *idata, *idata_new;

   edje_object_part_geometry_get(edje, "ephoto.swallow.image", &x, &y, &w, &h);
   edje_object_part_geometry_get(edje, "ephoto.swallow.cropper", &cx, &cy, &cw,
                                 &ch);
   evas_object_image_size_get(ec->image, &iw, &ih);

   idata =
     evas_object_image_data_get(ec->image, EINA_FALSE);

   scalex = (double)(cx - x) / (double)w;
   scaley = (double)(cy - y) / (double)h;
   scalew = (double)cw / (double)w;
   scaleh = (double)ch / (double)h;

   nx = iw * scalex;
   ny = ih * scaley;
   nw = iw * scalew;
   nh = ih * scaleh;

   index = 0;
   idata_new = malloc(sizeof(unsigned int) * nw * nh);

   for (i = 0; i < nh; i++)
     {
        tmpy = (i + ny) * iw;
        for (j = 0; j < nw; j++)
          {
             tmpx = j + nx;
             ind = tmpy + tmpx;
             idata_new[index] = idata[ind];
             index++;
          }
     }
   elm_table_unpack(ec->image_parent, ec->box);
   elm_layout_content_unset(ec->layout, "ephoto.swallow.image");
   elm_table_pack(ec->image_parent, ec->image, 0, 0, 1, 1);
   ephoto_single_browser_image_data_done(ec->main,
                                         idata_new, nw, nh);
   evas_object_del(ec->cropper);
   evas_object_del(ec->layout);
   evas_object_del(ec->box);
   ephoto_editor_del(ec->editor, ec->parent);
}

static void
_cancel_crop(void *data, Evas_Object *obj EINA_UNUSED,
             void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;

   elm_table_unpack(ec->image_parent, ec->box);
   elm_layout_content_unset(ec->layout, "ephoto.swallow.image");
   elm_table_pack(ec->image_parent, ec->image, 0, 0, 1, 1);
   ephoto_single_browser_cancel_editing(ec->main);
   evas_object_del(ec->cropper);
   evas_object_del(ec->layout);
   evas_object_del(ec->box);
   ephoto_editor_del(ec->editor, ec->parent);
}

static void
_cropper_both_mouse_move(void *data, Evas_Object *obj EINA_UNUSED,
                         const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;
   Evas_Coord mx, my, cx, cy, cw, ch, nx, ny, lx, ly, lw, lh;

   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, &cw, &ch);
   evas_object_geometry_get(ec->layout, &lx, &ly, &lw, &lh);

   if (mx < lx)
     mx = lx;
   else if (mx > lx + lw)
     mx = lx + lw;
   if (my < ly)
     my = ly;
   else if (my > ly + lh)
     my = ly + lh;

   nx = mx - ec->startx;
   ny = my - ec->starty;
   ec->startx = mx;
   ec->starty = my;

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   if (!strcmp(source, "handle1"))
     msg->val[0] = 1;
   else if (!strcmp(source, "handle3"))
     msg->val[0] = 3;
   else if (!strcmp(source, "handle5"))
     msg->val[0] = 5;
   else if (!strcmp(source, "handle7"))
     msg->val[0] = 7;

   msg->val[1] = nx;
   msg->val[2] = ny;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static void
_cropper_both_mouse_up(void *data, Evas_Object *obj EINA_UNUSED,
                       const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;

   edje_object_signal_callback_del_full(ec->cropper, "mouse,move", source,
                                        _cropper_both_mouse_move, ec);
   edje_object_signal_callback_del_full(ec->cropper, "mouse,up,1", source,
                                        _cropper_both_mouse_up, ec);
   ec->resizing = 0;
}

static void
_cropper_resize_both(void *data, Evas_Object *obj EINA_UNUSED,
                     const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;
   Evas_Coord mx, my, cx, cy;

   ec->resizing = 1;
   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, 0, 0);
   ec->offsetx = mx - cx;
   ec->offsety = my - cy;
   ec->startx = mx;
   ec->starty = my;

   edje_object_signal_callback_add(ec->cropper, "mouse,move", source,
                                   _cropper_both_mouse_move, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,up,1", source,
                                   _cropper_both_mouse_up, ec);
}

static void
_cropper_horiz_mouse_move(void *data, Evas_Object *obj EINA_UNUSED,
                          const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;
   Evas_Coord mx, cx, cy, cw, ch, nx, lx, lw;

   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, 0);
   evas_object_geometry_get(ec->cropper, &cx, &cy, &cw, &ch);
   evas_object_geometry_get(ec->layout, &lx, 0, &lw, 0);

   if (mx < lx)
     mx = lx;
   else if (mx > lx + lw)
     mx = lx + lw;

   nx = mx - ec->startx;
   ec->startx = mx;

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   if (!strcmp(source, "handle4"))
     msg->val[0] = 4;
   else if (!strcmp(source, "handle8"))
     msg->val[0] = 8;
   msg->val[1] = nx;
   msg->val[2] = 0;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static void
_cropper_horiz_mouse_up(void *data, Evas_Object *obj EINA_UNUSED,
                        const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;

   edje_object_signal_callback_del_full(ec->cropper, "mouse,move", source,
                                        _cropper_horiz_mouse_move, ec);
   edje_object_signal_callback_del_full(ec->cropper, "mouse,up,1", source,
                                        _cropper_horiz_mouse_up, ec);
   ec->resizing = 0;
}

static void
_cropper_resize_horiz(void *data, Evas_Object *obj EINA_UNUSED,
                      const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Evas_Coord mx, my, cx, cy;

   ec->resizing = 1;
   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, 0, 0);
   ec->offsetx = mx - cx;
   ec->offsety = my - cy;
   ec->startx = mx;
   ec->starty = my;

   edje_object_signal_callback_add(ec->cropper, "mouse,move", source,
                                   _cropper_horiz_mouse_move, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,up,1", source,
                                   _cropper_horiz_mouse_up, ec);
}

static void
_cropper_vert_mouse_move(void *data, Evas_Object *obj EINA_UNUSED,
                         const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;
   Evas_Coord my, cx, cy, cw, ch, ny, ly, lh;

   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), 0, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, &cw, &ch);
   evas_object_geometry_get(ec->layout, 0, &ly, 0, &lh);

   if (my < ly)
     my = ly;
   else if (my > ly + lh)
     my = ly + lh;

   ny = my - ec->starty;
   ec->starty = my;

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   if (!strcmp(source, "handle2"))
     msg->val[0] = 2;
   else if (!strcmp(source, "handle6"))
     msg->val[0] = 6;
   msg->val[1] = 0;
   msg->val[2] = ny;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static void
_cropper_vert_mouse_up(void *data, Evas_Object *obj EINA_UNUSED,
                       const char *emission EINA_UNUSED, const char *source)
{
   Ephoto_Cropper *ec = data;

   edje_object_signal_callback_del_full(ec->cropper, "mouse,move", source,
                                        _cropper_vert_mouse_move, ec);
   edje_object_signal_callback_del_full(ec->cropper, "mouse,up,1", source,
                                        _cropper_vert_mouse_up, ec);
   ec->resizing = 0;
}

static void
_cropper_resize_vert(void *data, Evas_Object *obj EINA_UNUSED,
                     const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Evas_Coord mx, my, cx, cy;

   ec->resizing = 1;
   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, 0, 0);
   ec->offsetx = mx - cx;
   ec->offsety = my - cy;
   ec->startx = mx;
   ec->starty = my;

   edje_object_signal_callback_add(ec->cropper, "mouse,move", source,
                                   _cropper_vert_mouse_move, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,up,1", source,
                                   _cropper_vert_mouse_up, ec);
}

static void
_cropper_mouse_move(void *data, Evas_Object *obj EINA_UNUSED,
                    const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;

   if (!ec->resizing)
     {
        Edje_Message_Int_Set *msg;
        Evas_Coord mx, my, cx, cy, cw, ch, nx, ny, lx, ly, lw, lh;

        evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper),
                                   &mx, &my);
        evas_object_geometry_get(ec->cropper, &cx, &cy, &cw, &ch);
        evas_object_geometry_get(ec->layout, &lx, &ly, &lw, &lh);

        if (mx < lx)
          mx = lx;
        else if (mx > lx + lw)
          mx = lx + lw;
        if (my < ly)
          my = ly;
        else if (my > ly + lh)
          my = ly + lh;

        nx = mx - ec->startx;
        ny = my - ec->starty;
        ec->startx = mx;
        ec->starty = my;

        msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
        msg->count = 3;
        msg->val[0] = 0;
        msg->val[1] = nx;
        msg->val[2] = ny;
        edje_object_message_send(elm_layout_edje_get(ec->layout),
                                 EDJE_MESSAGE_INT_SET, 1, msg);
     }
}

static void
_cropper_mouse_up(void *data, Evas_Object *obj EINA_UNUSED,
                  const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;

   edje_object_signal_callback_del_full(ec->cropper, "mouse,move", "dragger",
                                        _cropper_mouse_move, ec);
   edje_object_signal_callback_del_full(ec->cropper, "mouse,up,1", "dragger",
                                        _cropper_mouse_up, ec);
}

static void
_cropper_move(void *data, Evas_Object *obj EINA_UNUSED,
              const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Evas_Coord mx, my, cx, cy;

   evas_pointer_canvas_xy_get(evas_object_evas_get(ec->cropper), &mx, &my);
   evas_object_geometry_get(ec->cropper, &cx, &cy, 0, 0);
   ec->startx = mx;
   ec->starty = my;
   ec->offsetx = mx - cx;
   ec->offsety = my - cy;

   edje_object_signal_callback_add(ec->cropper, "mouse,move", "dragger",
                                   _cropper_mouse_move, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,up,1", "dragger",
                                   _cropper_mouse_up, ec);
}

static void
_image_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
              void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Edje_Message_Int_Set *msg;

   Evas_Coord sx, sy, sw, sh, ix, iy, iw, ih, diffw, diffh;

   evas_object_geometry_get(ec->layout, &sx, &sy, &sw, &sh);
   evas_object_image_size_get(ec->image, &iw, &ih);

   Evas_Coord nw, nh;

   if (sw > sh)
     {
        nw = sw;
        nh = ih * ((double)sw / (double)iw);
        if (nh > sh)
          {
             Evas_Coord onw, onh;

             onw = nw;
             onh = nh;
             nh = sh;
             nw = onw * ((double)nh / (double)onh);
          }
     }
   else
     {
        nh = sh;
        nw = iw * ((double)sh / (double)ih);
        if (nw > sw)
          {
             Evas_Coord onw, onh;

             onw = nw;
             onh = nh;
             nw = sw;
             nh = onh * ((double)nw / (double)onw);
          }
     }
   diffw = sw - nw;
   diffh = sh - nh;
   diffw /= 2;
   diffh /= 2;
   ix = sx + diffw;
   iy = sy + diffh;

   evas_object_resize(ec->layout, nw, nh);
   evas_object_move(ec->layout, ix, iy);

   msg = alloca(sizeof(Edje_Message_Int_Set) + (3 * sizeof(int)));
   msg->count = 3;
   msg->val[0] = 9;
   msg->val[1] = 0;
   msg->val[2] = 0;
   edje_object_message_send(elm_layout_edje_get(ec->layout),
                            EDJE_MESSAGE_INT_SET, 1, msg);
}

static Eina_Bool
_crop_reset(void *data, int type EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   _reset_crop(data, NULL, NULL);

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_crop_apply(void *data, int type EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   _apply_crop(data, NULL, NULL);

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_crop_cancel(void *data, int type EINA_UNUSED,
             void *event_info EINA_UNUSED)
{
   _cancel_crop(data, NULL, NULL);

   return ECORE_CALLBACK_PASS_ON;
}

static void
_editor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   Ephoto_Cropper *ec = data;
   Ecore_Event_Handler *handler;

   EINA_LIST_FREE(ec->handlers, handler)
     ecore_event_handler_del(handler);

   free(ec);
}

void
ephoto_cropper_add(Ephoto *ephoto, Evas_Object *main, Evas_Object *parent,
                   Evas_Object *image_parent, Evas_Object *image)
{
   Ephoto_Cropper *ec;
   Evas_Coord w, h;

   EINA_SAFETY_ON_NULL_GOTO(image, error);

   ec = calloc(1, sizeof(Ephoto_Cropper));
   EINA_SAFETY_ON_NULL_GOTO(ec, error);

   ec->resizing = 0;
   ec->main = main;
   ec->parent = parent;
   ec->image_parent = image_parent;
   ec->image = image;

   evas_object_image_size_get(image, &w, &h);

   ec->box = elm_box_add(image_parent);
   elm_box_homogeneous_set(ec->box, EINA_TRUE);
   elm_box_horizontal_set(ec->box, EINA_TRUE);
   EPHOTO_EXPAND(ec->box);
   EPHOTO_FILL(ec->box);
   elm_table_pack(image_parent, ec->box, 0, 0, 1, 1);
   evas_object_show(ec->box);

   ec->layout = elm_layout_add(ec->box);
   elm_layout_file_set(ec->layout, PACKAGE_DATA_DIR "/themes/ephoto.edj",
                       "ephoto,image,cropper,base");
   EPHOTO_EXPAND(ec->layout);
   EPHOTO_FILL(ec->layout);
   elm_box_pack_end(ec->box, ec->layout);
   evas_object_show(ec->layout);

   EPHOTO_EXPAND(ec->image);
   EPHOTO_FILL(ec->image);
   elm_layout_content_set(ec->layout, "ephoto.swallow.image", ec->image);
   evas_object_show(ec->image);

   ec->cropper = edje_object_add(evas_object_evas_get(ec->layout));
   edje_object_file_set(ec->cropper, PACKAGE_DATA_DIR "/themes/ephoto.edj",
                        "ephoto,image,cropper");
   edje_object_signal_callback_add(elm_layout_edje_get(ec->layout),
                                   "cropper,changed", "ephoto.swallow.cropper",
                                   _calculate_cropper_size,
                                   ec);
   elm_layout_content_set(ec->layout, "ephoto.swallow.cropper", ec->cropper);
   evas_object_show(ec->cropper);

   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "dragger",
                                   _cropper_move, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle1",
                                   _cropper_resize_both, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle2",
                                   _cropper_resize_vert, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle3",
                                   _cropper_resize_both, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle4",
                                   _cropper_resize_horiz, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle5",
                                   _cropper_resize_both, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle6",
                                   _cropper_resize_vert, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle7",
                                   _cropper_resize_both, ec);
   edje_object_signal_callback_add(ec->cropper, "mouse,down,1", "handle8",
                                   _cropper_resize_horiz, ec);

   evas_object_event_callback_add(ec->layout, EVAS_CALLBACK_RESIZE,
                                  _image_resize, ec);

   ec->editor = ephoto_editor_add(ephoto, parent, _("Crop Image"),
                                  "ec", ec);
   evas_object_event_callback_add(ec->editor, EVAS_CALLBACK_DEL,
                                  _editor_del, ec);

   ec->croph = elm_slider_add(ec->editor);
   elm_slider_min_max_set(ec->croph, 1, h);
   elm_slider_step_set(ec->croph, 1);
   elm_slider_unit_format_set(ec->croph, "%1.0f");
   elm_slider_indicator_format_set(ec->croph, "%1.0f");
   elm_object_text_set(ec->croph, _("Height"));
   EPHOTO_WEIGHT(ec->croph, EVAS_HINT_EXPAND, EVAS_HINT_FILL);
   EPHOTO_ALIGN(ec->croph, EVAS_HINT_FILL, 0.5);
   elm_box_pack_start(ec->editor, ec->croph);
   evas_object_smart_callback_add(ec->croph, "slider,drag,stop",
                                  _cropper_changed_height, ec);
   evas_object_show(ec->croph);

   ec->cropw = elm_slider_add(ec->editor);
   elm_slider_min_max_set(ec->cropw, 1, w);
   elm_slider_step_set(ec->cropw, 1);
   elm_slider_unit_format_set(ec->cropw, "%1.0f");
   elm_slider_indicator_format_set(ec->cropw, "%1.0f");
   elm_object_text_set(ec->cropw, _("Width"));
   EPHOTO_WEIGHT(ec->cropw, EVAS_HINT_EXPAND, EVAS_HINT_FILL);
   EPHOTO_ALIGN(ec->cropw, EVAS_HINT_FILL, 0.5);
   elm_box_pack_start(ec->editor, ec->cropw);
   evas_object_smart_callback_add(ec->cropw, "slider,drag,stop",
                                  _cropper_changed_width, ec);
   evas_object_show(ec->cropw);

   ec->handlers =
     eina_list_append(ec->handlers,
                      ecore_event_handler_add(EPHOTO_EVENT_EDITOR_RESET,
                                              _crop_reset, ec));
   ec->handlers =
     eina_list_append(ec->handlers,
                      ecore_event_handler_add(EPHOTO_EVENT_EDITOR_APPLY,
                                              _crop_apply, ec));
   ec->handlers =
     eina_list_append(ec->handlers,
                      ecore_event_handler_add(EPHOTO_EVENT_EDITOR_CANCEL,
                                              _crop_cancel, ec));

   return;

error:
   return;
}

