X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Flib%2Felm_photocam.c;h=021ddcf1688d2bf05b6f900fc6505f219723bd74;hb=f8c7c0cf477b77aa52664e0cdf7d059372433980;hp=de13d251e75649989841b458c308c18687f88586;hpb=49e5760106ad15d0d4f3d6d4fffcb91a21359da7;p=framework%2Fuifw%2Felementary.git diff --git a/src/lib/elm_photocam.c b/src/lib/elm_photocam.c index de13d25..021ddcf 100644 --- a/src/lib/elm_photocam.c +++ b/src/lib/elm_photocam.c @@ -1,64 +1,16 @@ #include #include "elm_priv.h" +#include "els_scroller.h" -/** - * @defgroup Photocam Photocam - * @ingroup Elementary - * - * This is a widget specifically for displaying high-resolution digital - * camera photos giving speedy feedback (fast load), low memory footprint - * and zooming and panning as well as fitting logic. It is entirely focused - * on jpeg images, and takes advantage of properties of the jpeg format (via - * evas loader features in the jpeg loader). - * - * Signals that you can add callbacks for are: - * - * clicked - This is called when a user has clicked the photo without dragging - * around. - * - * press - This is called when a user has pressed down on the photo. - * - * longpressed - This is called when a user has pressed down on the photo for - * a long time without dragging around. - * - * clicked,double - This is called when a user has double-clicked the photo. - * - * load - Photo load begins. - * - * loaded - This is called when the image file load is complete for the first - * view (low resolution blurry version). - * - * load,details - Photo detailed data load begins. - * - * loaded,details - This is called when the image file load is complete for the - * detailed image data (full resolution needed). - * - * zoom,start - Zoom animation started. - * - * zoom,stop - Zoom animation stopped. - * - * zoom,change - Zoom changed when using an auto zoom mode. - * - * scroll - the content has been scrolled (moved) - * - * scroll,anim,start - scrolling animation has started - * - * scroll,anim,stop - scrolling animation has stopped - * - * scroll,drag,start - dragging the contents around has started - * - * scroll,drag,stop - dragging the contents around has stopped - * - * --- - * +/* * TODO (maybe - optional future stuff): - * + * * 1. wrap photo in theme edje so u can have styling around photo (like white * photo bordering). * 2. exif handling * 3. rotation flags in exif handling (nasty! should have rot in evas) - * */ + typedef struct _Widget_Data Widget_Data; typedef struct _Pan Pan; typedef struct _Grid Grid; @@ -68,10 +20,10 @@ struct _Grid_Item { Widget_Data *wd; Evas_Object *img; - struct - { - int x, y, w, h; - } src, out; + struct + { + int x, y, w, h; + } src, out; Eina_Bool want : 1; Eina_Bool have : 1; }; @@ -92,33 +44,49 @@ struct _Widget_Data Evas_Object *obj; Evas_Object *scr; Evas_Object *pan_smart; + Evas_Object *gest; + double gest_start; + Pan *pan; Evas_Coord pan_x, pan_y, minw, minh; double zoom; Elm_Photocam_Zoom_Mode mode; + Evas_Coord pvx, pvy, px, py, zoom_point_x, zoom_point_y; + struct + { + int imx, imy; + struct + { + int x_start, y_start; + int x_end, y_end; + double t_start; + double t_end; + Ecore_Animator *animator; + } bounce; + } gzoom; const char *file; - + Ecore_Job *calc_job; Ecore_Timer *scr_timer; Ecore_Timer *long_timer; Ecore_Animator *zoom_animator; double t_start, t_end; - struct - { - int imw, imh; - int w, h; - int ow, oh, nw, nh; - struct - { - double x, y; - } spos; - } size; struct - { - Eina_Bool show : 1; - Evas_Coord x, y ,w ,h; - } show; + { + int imw, imh; + int w, h; + int ow, oh, nw, nh; + struct + { + double x, y; + } spos; + } size; + struct + { + Eina_Bool show : 1; + Evas_Coord x, y ,w ,h; + } show; int tsize; Evas_Object *img; // low res version of image (scale down == 8) int nosmooth; @@ -129,6 +97,9 @@ struct _Widget_Data Eina_Bool longpressed : 1; Eina_Bool on_hold : 1; Eina_Bool paused : 1; + Eina_Bool do_region : 1; + Eina_Bool do_gesture : 1; + Eina_Bool zoom_gest : 1; }; struct _Pan @@ -140,14 +111,55 @@ struct _Pan static const char *widtype = NULL; static void _del_hook(Evas_Object *obj); static void _theme_hook(Evas_Object *obj); +static void _on_focus_hook(void *data, Evas_Object *obj); //static void _show_region_hook(void *data, Evas_Object *obj); static void _sizing_eval(Evas_Object *obj); static void _calc_job(void *data); +static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, + Evas_Callback_Type type, void *event_info); static void grid_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh); static void grid_clear(Evas_Object *obj, Grid *g); static Grid *grid_create(Evas_Object *obj); static void grid_load(Evas_Object *obj, Grid *g); +static const char SIG_CLICKED[] = "clicked"; +static const char SIG_PRESS[] = "press"; +static const char SIG_LONGPRESSED[] = "longpressed"; +static const char SIG_CLICKED_DOUBLE[] = "clicked,double"; +static const char SIG_LOAD[] = "load"; +static const char SIG_LOADED[] = "loaded"; +static const char SIG_LOAD_DETAIL[] = "load,detail"; +static const char SIG_LOADED_DETAIL[] = "loaded,detail"; +static const char SIG_ZOOM_START[] = "zoom,start"; +static const char SIG_ZOOM_STOP[] = "zoom,stop"; +static const char SIG_ZOOM_CHANGE[] = "zoom,change"; +static const char SIG_SCROLL[] = "scroll"; +static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start"; +static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop"; +static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start"; +static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop"; + +static const Evas_Smart_Cb_Description _signals[] = { + {SIG_CLICKED, ""}, + {SIG_PRESS, ""}, + {SIG_LONGPRESSED, ""}, + {SIG_CLICKED_DOUBLE, ""}, + {SIG_LOAD, ""}, + {SIG_LOADED, ""}, + {SIG_LOAD_DETAIL, ""}, + {SIG_LOADED_DETAIL, ""}, + {SIG_ZOOM_START, ""}, + {SIG_ZOOM_STOP, ""}, + {SIG_ZOOM_CHANGE, ""}, + {SIG_SCROLL, ""}, + {SIG_SCROLL_ANIM_START, ""}, + {SIG_SCROLL_ANIM_STOP, ""}, + {SIG_SCROLL_DRAG_START, ""}, + {SIG_SCROLL_DRAG_STOP, ""}, + {NULL, NULL} +}; + + static int nearest_pow2(int num) { @@ -170,15 +182,18 @@ img_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Co ay = 0; gw = wd->size.w; gh = wd->size.h; - if (ow > gw) ax = (ow - gw) / 2; - if (oh > gh) ay = (oh - gh) / 2; + if (!wd->zoom_gest) + { + if (ow > gw) ax = (ow - gw) / 2; + if (oh > gh) ay = (oh - gh) / 2; + } evas_object_move(wd->img, ox + 0 - px + ax, oy + 0 - py + ay); evas_object_resize(wd->img, gw, gh); if (wd->show.show) { - wd->show.show = EINA_FALSE; - elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h); + wd->show.show = EINA_FALSE; + elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h); } } @@ -193,14 +208,17 @@ grid_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord o ay = 0; gw = wd->size.w; gh = wd->size.h; - if (ow > gw) ax = (ow - gw) / 2; - if (oh > gh) ay = (oh - gh) / 2; + if (!wd->zoom_gest) + { + if (ow > gw) ax = (ow - gw) / 2; + if (oh > gh) ay = (oh - gh) / 2; + } for (y = 0; y < g->gh; y++) { for (x = 0; x < g->gw; x++) { int tn, xx, yy, ww, hh; - + tn = (y * g->gw) + x; xx = g->grid[tn].out.x; yy = g->grid[tn].out.y; @@ -238,17 +256,17 @@ grid_clear(Evas_Object *obj, Grid *g) for (x = 0; x < g->gw; x++) { int tn; - + tn = (y * g->gw) + x; evas_object_del(g->grid[tn].img); if (g->grid[tn].want) { wd->preload_num--; - if (wd->preload_num == 0) + if (!wd->preload_num) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,stop", "elm"); - evas_object_smart_callback_call(obj, "loaded,detail", NULL); + evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL); } } } @@ -270,11 +288,11 @@ _tile_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void evas_object_show(git->img); git->have = 1; git->wd->preload_num--; - if (git->wd->preload_num == 0) + if (!git->wd->preload_num) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(git->wd->scr), "elm,state,busy,stop", "elm"); - evas_object_smart_callback_call(git->wd->obj, "loaded,detail", NULL); + evas_object_smart_callback_call(git->wd->obj, SIG_LOADED_DETAIL, NULL); } } } @@ -293,20 +311,33 @@ grid_create(Evas_Object *obj) Widget_Data *wd = elm_widget_data_get(obj); int x, y; Grid *g; - + if (!wd) return NULL; g = calloc(1, sizeof(Grid)); - + if (!g) return NULL; + g->zoom = grid_zoom_calc(wd->zoom); g->tsize = wd->tsize; g->iw = wd->size.imw; g->ih = wd->size.imh; - + g->w = g->iw / g->zoom; g->h = g->ih / g->zoom; - if (g->zoom >= 8) return NULL; - g->gw = (g->w + g->tsize - 1) / g->tsize; - g->gh = (g->h + g->tsize - 1) / g->tsize; + if (g->zoom >= 8) + { + free(g); + return NULL; + } + if (wd->do_region) + { + g->gw = (g->w + g->tsize - 1) / g->tsize; + g->gh = (g->h + g->tsize - 1) / g->tsize; + } + else + { + g->gw = 1; + g->gh = 1; + } g->grid = calloc(1, sizeof(Grid_Item) * g->gw * g->gh); if (!g->grid) { @@ -319,7 +350,7 @@ grid_create(Evas_Object *obj) for (x = 0; x < g->gw; x++) { int tn; - + tn = (y * g->gw) + x; g->grid[tn].src.x = x * g->tsize; if (x == (g->gw - 1)) @@ -331,25 +362,26 @@ grid_create(Evas_Object *obj) g->grid[tn].src.h = g->h - ((g->gh - 1) * g->tsize); else g->grid[tn].src.h = g->tsize; - + g->grid[tn].out.x = g->grid[tn].src.x; g->grid[tn].out.y = g->grid[tn].src.y; g->grid[tn].out.w = g->grid[tn].src.w; g->grid[tn].out.h = g->grid[tn].src.h; - + g->grid[tn].wd = wd; - g->grid[tn].img = - evas_object_image_add(evas_object_evas_get(obj)); + g->grid[tn].img = + evas_object_image_add(evas_object_evas_get(obj)); + evas_object_image_load_orientation_set(g->grid[tn].img, EINA_TRUE); evas_object_image_scale_hint_set - (g->grid[tn].img, EVAS_IMAGE_SCALE_HINT_DYNAMIC); - evas_object_pass_events_set(g->grid[tn].img, 1); - evas_object_smart_member_add(g->grid[tn].img, + (g->grid[tn].img, EVAS_IMAGE_SCALE_HINT_DYNAMIC); + evas_object_pass_events_set(g->grid[tn].img, EINA_TRUE); + evas_object_smart_member_add(g->grid[tn].img, wd->pan_smart); elm_widget_sub_object_add(obj, g->grid[tn].img); evas_object_image_filled_set(g->grid[tn].img, 1); - evas_object_event_callback_add(g->grid[tn].img, + evas_object_event_callback_add(g->grid[tn].img, EVAS_CALLBACK_IMAGE_PRELOADED, - _tile_preloaded, + _tile_preloaded, &(g->grid[tn])); } } @@ -361,23 +393,19 @@ grid_load(Evas_Object *obj, Grid *g) { Widget_Data *wd = elm_widget_data_get(obj); int x, y; - Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, gw, gh, ax, ay, tx, ty; + Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, gw, gh, tx, ty; if (!wd) return; evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh); evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh); - ax = 0; - ay = 0; gw = wd->size.w; gh = wd->size.h; - if (ow > gw) ax = (ow - gw) / 2; - if (oh > gh) ay = (oh - gh) / 2; for (y = 0; y < g->gh; y++) { for (x = 0; x < g->gw; x++) { int tn, xx, yy, ww, hh; Eina_Bool visible = EINA_FALSE; - + tn = (y * g->gw) + x; xx = g->grid[tn].out.x; yy = g->grid[tn].out.y; @@ -395,9 +423,7 @@ grid_load(Evas_Object *obj, Grid *g) yy = (gh * yy) / g->h; hh = ((gh * (ty + hh)) / g->h) - yy; } -// xx += ax; -// yy += ay; - if (ELM_RECTS_INTERSECT(xx - wd->pan_x + ox, + if (ELM_RECTS_INTERSECT(xx - wd->pan_x + ox, yy - wd->pan_y + oy, ww, hh, cvx, cvy, cvw, cvh)) @@ -413,24 +439,24 @@ grid_load(Evas_Object *obj, Grid *g) g->grid[tn].src.y, g->grid[tn].src.w, g->grid[tn].src.h); - evas_object_image_file_set(g->grid[tn].img, wd->file, NULL); + evas_object_image_file_set(g->grid[tn].img, wd->file, NULL); evas_object_image_preload(g->grid[tn].img, 0); wd->preload_num++; if (wd->preload_num == 1) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,start", "elm"); - evas_object_smart_callback_call(obj, "load,detail", NULL); + evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL); } } else if ((g->grid[tn].want) && (!visible)) { wd->preload_num--; - if (wd->preload_num == 0) + if (!wd->preload_num) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,stop", "elm"); - evas_object_smart_callback_call(obj, "loaded,detail", NULL); + evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL); } g->grid[tn].want = 0; evas_object_hide(g->grid[tn].img); @@ -476,26 +502,26 @@ _smooth_update(Evas_Object *obj) for (x = 0; x < g->gw; x++) { int tn; - + tn = (y * g->gw) + x; - evas_object_image_smooth_scale_set(g->grid[tn].img, (wd->nosmooth == 0)); + evas_object_image_smooth_scale_set(g->grid[tn].img, (!wd->nosmooth)); } } } - evas_object_image_smooth_scale_set(wd->img, (wd->nosmooth == 0)); + evas_object_image_smooth_scale_set(wd->img, (!wd->nosmooth)); } static void _grid_raise(Grid *g) { int x, y; - + for (y = 0; y < g->gh; y++) { for (x = 0; x < g->gw; x++) { int tn; - + tn = (y * g->gw) + x; evas_object_raise(g->grid[tn].img); } @@ -508,7 +534,7 @@ _scr_timeout(void *data) Widget_Data *wd = elm_widget_data_get(data); if (!wd) return ECORE_CALLBACK_CANCEL; wd->nosmooth--; - if (wd->nosmooth == 0) _smooth_update(data); + if (!wd->nosmooth) _smooth_update(data); wd->scr_timer = NULL; return ECORE_CALLBACK_CANCEL; } @@ -544,13 +570,13 @@ _main_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void } if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); - evas_object_smart_callback_call(data, "loaded", NULL); + evas_object_smart_callback_call(data, SIG_LOADED, NULL); wd->preload_num--; - if (wd->preload_num == 0) + if (!wd->preload_num) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,stop", "elm"); - evas_object_smart_callback_call(obj, "loaded,detail", NULL); + evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL); } } @@ -582,7 +608,7 @@ zoom_do(Evas_Object *obj, double t) { Eina_List *l, *l_next; Grid *g; - + EINA_LIST_FOREACH_SAFE(wd->grids, l, l_next, g) { if (g->dead) @@ -619,9 +645,9 @@ _zoom_anim(void *data) if (!go) { wd->nosmooth--; - if (wd->nosmooth == 0) _smooth_update(data); + if (!wd->nosmooth) _smooth_update(data); wd->zoom_animator = NULL; - evas_object_smart_callback_call(obj, "zoom,stop", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL); } return go; } @@ -630,7 +656,7 @@ static void _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { Widget_Data *wd = elm_widget_data_get(data); -// Evas_Event_Mouse_Move *ev = event_info; + // Evas_Event_Mouse_Move *ev = event_info; if (!wd) return; } @@ -641,7 +667,7 @@ _long_press(void *data) if (!wd) return ECORE_CALLBACK_CANCEL; wd->long_timer = NULL; wd->longpressed = EINA_TRUE; - evas_object_smart_callback_call(data, "longpressed", NULL); + evas_object_smart_callback_call(data, SIG_LONGPRESSED, NULL); return ECORE_CALLBACK_CANCEL; } @@ -655,14 +681,14 @@ _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE; else wd->on_hold = EINA_FALSE; if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) - evas_object_smart_callback_call(data, "clicked,double", NULL); + evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, NULL); else - evas_object_smart_callback_call(data, "press", NULL); + evas_object_smart_callback_call(data, SIG_PRESS, NULL); wd->longpressed = EINA_FALSE; if (wd->long_timer) ecore_timer_del(wd->long_timer); - wd->long_timer = ecore_timer_add(1.0, _long_press, data); + wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data); } - + static void _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { @@ -678,10 +704,10 @@ _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void * wd->long_timer = NULL; } if (!wd->on_hold) - evas_object_smart_callback_call(data, "clicked", NULL); + evas_object_smart_callback_call(data, SIG_CLICKED, NULL); wd->on_hold = EINA_FALSE; } - + static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL; static void @@ -701,17 +727,35 @@ _del_hook(Evas_Object *obj) if (wd->calc_job) ecore_job_del(wd->calc_job); if (wd->scr_timer) ecore_timer_del(wd->scr_timer); if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator); + if (wd->gzoom.bounce.animator) ecore_animator_del(wd->gzoom.bounce.animator); if (wd->long_timer) ecore_timer_del(wd->long_timer); free(wd); } static void +_on_focus_hook(void *data __UNUSED__, Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + if (elm_widget_focus_get(obj)) + { + edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm"); + evas_object_focus_set(wd->obj, EINA_TRUE); + } + else + { + edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm"); + evas_object_focus_set(wd->obj, EINA_FALSE); + } +} + +static void _theme_hook(Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_object_theme_set(obj, wd->scr, "photocam", "base", elm_widget_style_get(obj)); -// edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale); + // edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale); _sizing_eval(obj); } @@ -733,11 +777,11 @@ _sizing_eval(Evas_Object *obj) Widget_Data *wd = elm_widget_data_get(obj); Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1; if (!wd) return; -// evas_object_size_hint_min_get(wd->scr, &minw, &minh); + // evas_object_size_hint_min_get(wd->scr, &minw, &minh); evas_object_size_hint_max_get(wd->scr, &maxw, &maxh); -// minw = -1; -// minh = -1; -// if (wd->mode != ELM_LIST_LIMIT) minw = -1; + // minw = -1; + // minh = -1; + // if (wd->mode != ELM_LIST_LIMIT) minw = -1; evas_object_size_hint_min_set(obj, minw, minh); evas_object_size_hint_max_set(obj, maxw, maxh); } @@ -807,6 +851,13 @@ _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) } static void +_pan_min_get(Evas_Object *obj __UNUSED__, Evas_Coord *x, Evas_Coord *y) +{ + if (x) *x = 0; + if (y) *y = 0; +} + +static void _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) { Pan *sd = evas_object_smart_data_get(obj); @@ -860,11 +911,13 @@ _pan_calculate(Evas_Object *obj) Grid *g; if (!sd) return; evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); - img_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh); + img_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, + ox - sd->wd->gzoom.imx, oy - sd->wd->gzoom.imy, ow, oh); EINA_LIST_FOREACH(sd->wd->grids, l, g) { grid_load(sd->wd->obj, g); - grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh); + grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, + ox - sd->wd->gzoom.imx, oy - sd->wd->gzoom.imy, ow, oh); } } @@ -912,41 +965,357 @@ _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__ static void _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - evas_object_smart_callback_call(data, "scroll,anim,start", NULL); + evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL); } static void _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - evas_object_smart_callback_call(data, "scroll,anim,stop", NULL); + evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL); } static void _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - evas_object_smart_callback_call(data, "scroll,drag,start", NULL); + evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL); } static void _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - evas_object_smart_callback_call(data, "scroll,drag,stop", NULL); + evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL); } static void _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { - evas_object_smart_callback_call(data, "scroll", NULL); + evas_object_smart_callback_call(data, SIG_SCROLL, NULL); +} + +static Eina_Bool +_event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, + Evas_Callback_Type type, void *event_info) +{ + double zoom; + if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE; + Evas_Event_Key_Down *ev = event_info; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return EINA_FALSE; + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE; + + Evas_Coord x = 0; + Evas_Coord y = 0; + Evas_Coord step_x = 0; + Evas_Coord step_y = 0; + Evas_Coord v_w = 0; + Evas_Coord v_h = 0; + Evas_Coord page_x = 0; + Evas_Coord page_y = 0; + + elm_smart_scroller_child_pos_get(wd->scr, &x, &y); + elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y); + elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y); + elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h); + + if ((!strcmp(ev->keyname, "Left")) || + ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string))) + { + x -= step_x; + } + else if ((!strcmp(ev->keyname, "Right")) || + ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string))) + { + x += step_x; + } + else if ((!strcmp(ev->keyname, "Up")) || + ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string))) + { + y -= step_y; + } + else if ((!strcmp(ev->keyname, "Down")) || + ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string))) + { + y += step_y; + } + else if ((!strcmp(ev->keyname, "Prior")) || + ((!strcmp(ev->keyname, "KP_Prior")) && (!ev->string))) + { + if (page_y < 0) + y -= -(page_y * v_h) / 100; + else + y -= page_y; + } + else if ((!strcmp(ev->keyname, "Next")) || + ((!strcmp(ev->keyname, "KP_Next")) && (!ev->string))) + { + if (page_y < 0) + y += -(page_y * v_h) / 100; + else + y += page_y; + } + else if ((!strcmp(ev->keyname, "KP_Add"))) + { + zoom = elm_photocam_zoom_get(obj); + zoom -= 0.5; + elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL); + elm_photocam_zoom_set(obj, zoom); + return EINA_TRUE; + } + else if ((!strcmp(ev->keyname, "KP_Subtract"))) + { + zoom = elm_photocam_zoom_get(obj); + zoom += 0.5; + elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL); + elm_photocam_zoom_set(obj, zoom); + return EINA_TRUE; + } + else return EINA_FALSE; + + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + elm_smart_scroller_child_pos_set(wd->scr, x, y); + + return EINA_TRUE; +} + +Eina_Bool +_bounce_eval(void *_wd) +{ + Widget_Data *wd = (Widget_Data *)_wd; + double t, tt; + + if (!wd) return ECORE_CALLBACK_CANCEL; + if ((wd->gzoom.imx == wd->gzoom.bounce.x_end) && + (wd->gzoom.imy == wd->gzoom.bounce.y_end)) + { + wd->gzoom.imx = 0; + wd->gzoom.imy = 0; + wd->zoom_gest = EINA_FALSE; + wd->gzoom.bounce.animator = NULL; + _freeze_off(NULL, wd->obj, NULL); + return ECORE_CALLBACK_CANCEL; + } + + t = ecore_loop_time_get(); + tt = (t - wd->gzoom.bounce.t_start) / (wd->gzoom.bounce.t_end - wd->gzoom.bounce.t_start); + tt = 1.0 - tt; + tt = 1.0 - (tt * tt); + + if (t > wd->gzoom.bounce.t_end) + { + wd->gzoom.imx = 0; + wd->gzoom.imy = 0; + wd->zoom_gest = EINA_FALSE; + _freeze_off(NULL, wd->obj, NULL); + zoom_do(wd->obj, 1.0); + wd->gzoom.bounce.animator = NULL; + return ECORE_CALLBACK_CANCEL; + } + + if (wd->gzoom.imx != wd->gzoom.bounce.x_end) + wd->gzoom.imx = wd->gzoom.bounce.x_start * (1.0 - tt) + wd->gzoom.bounce.x_end * tt; + + if (wd->gzoom.imy != wd->gzoom.bounce.y_end) + wd->gzoom.imy = wd->gzoom.bounce.y_start * (1.0 - tt) + wd->gzoom.bounce.y_end * tt; + + zoom_do(wd->obj, 1.0 - (1.0 - tt)); + return ECORE_CALLBACK_RENEW; +} + +static void +_gzoom(Widget_Data *_wd, Evas_Coord px, Evas_Coord py, Elm_Gesture_Zoom_Info* gest) +{ + Widget_Data *wd = (Widget_Data *)_wd; + Evas_Coord rx, ry, rw, rh; + int regx, regy, regw, regh, ix, iy, iw, ih; + int xx, yy; + + if (!wd) return; + wd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL; + wd->zoom = wd->gest_start / gest->zoom; + wd->size.ow = wd->size.w; + wd->size.oh = wd->size.h; + elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry); + elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh); + if ((rw <= 0) || (rh <= 0)) return; + + wd->size.nw = (double)wd->size.imw / wd->zoom; + wd->size.nh = (double)wd->size.imh / wd->zoom; + + elm_photocam_image_region_get(wd->obj, ®x, ®y, ®w, ®h); + evas_object_geometry_get(wd->img, &ix, &iy, &iw, &ih); + + wd->pvx = gest->x; + wd->pvy = gest->y; + + xx = (px / wd->zoom) - wd->pvx; + yy = (py / wd->zoom) - wd->pvy; + wd->gzoom.imx = 0; + wd->gzoom.imy = 0; + + if ((xx < 0) || (rw > wd->size.nw)) + { + wd->gzoom.imx = xx; + xx = 0; + } + else if ((xx + rw) > wd->size.nw) + { + wd->gzoom.imx = xx + rw - wd->size.nw; + xx = wd->size.nw - rw; + } + + if ((yy < 0) || (rh > wd->size.nh)) + { + wd->gzoom.imy = yy; + yy = 0; + } + else if ((yy + rh) > wd->size.nh) + { + wd->gzoom.imy = yy + rh - wd->size.nh; + yy = wd->size.nh - rh; + } + + wd->size.spos.x = (double)(xx + (rw / 2)) / (double)(wd->size.nw); + wd->size.spos.y = (double)(yy + (rh / 2)) / (double)(wd->size.nh); + + zoom_do(wd->obj, 1.0); +} + +static Evas_Event_Flags +_gzoom_start(void *_wd, void *event_info) +{ + Widget_Data *wd = (Widget_Data *)_wd; + Elm_Gesture_Zoom_Info *p = (Elm_Gesture_Zoom_Info *) event_info; + Evas_Coord rw, rh; + int x,y,w,h; + double marginx = 0, marginy = 0; + + if (wd->gzoom.bounce.animator) + { + ecore_animator_del(wd->gzoom.bounce.animator); + wd->gzoom.bounce.animator = NULL; + } + wd->zoom_gest = EINA_TRUE; + _freeze_on(NULL, wd->obj, NULL); + + elm_photocam_image_region_get(wd->obj, &x, &y, &w, &h); + elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh); + + if (rw > wd->size.nw) + marginx = (rw - wd->size.nw) / 2; + if (rh > wd->size.nh) + marginy = (rh - wd->size.nh) / 2; + + wd->gest_start = wd->zoom; + + wd->zoom_point_x = x + ((p->x - marginx) * wd->zoom) + wd->gzoom.imx; + wd->zoom_point_y = y + ((p->y - marginy) * wd->zoom) + wd->gzoom.imy; + + return EVAS_EVENT_FLAG_NONE; +} + +static Evas_Event_Flags +_gzoom_move(void *_wd, void *event_info) +{ + Widget_Data *wd = (Widget_Data *)_wd; + Elm_Gesture_Zoom_Info *p = (Elm_Gesture_Zoom_Info *) event_info; + + _gzoom(wd, wd->zoom_point_x, wd->zoom_point_y, p); + return EVAS_EVENT_FLAG_NONE; +} + +static Evas_Event_Flags +_gzoom_end(void *_wd, void *event_info __UNUSED__) +{ + Widget_Data *wd = (Widget_Data *)_wd; + Evas_Coord rw, rh; + + elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh); + wd->gest_start = 1.0; + + if (wd->gzoom.imx || wd->gzoom.imy) + { + double t; + + t = ecore_loop_time_get(); + wd->gzoom.bounce.x_start = wd->gzoom.imx; + wd->gzoom.bounce.y_start = wd->gzoom.imy; + wd->gzoom.bounce.x_end = 0; + wd->gzoom.bounce.y_end = 0; + + if (rw > wd->size.nw && + rh > wd->size.nh) + { + Evas_Coord pw, ph; + double z; + + if ((wd->size.imw < rw) && (wd->size.imh < rh)) + { + wd->zoom = 1; + wd->size.nw = wd->size.imw; + wd->size.nh = wd->size.imh; + } + else + { + ph = (wd->size.imh * rw) / wd->size.imw; + if (ph > rh) + { + pw = (wd->size.imw * rh) / wd->size.imh; + ph = rh; + } + else + { + pw = rw; + } + if (wd->size.imw > wd->size.imh) + z = (double)wd->size.imw / pw; + else + z = (double)wd->size.imh / ph; + + wd->zoom = z; + wd->size.nw = pw; + wd->size.nh = ph; + } + wd->gzoom.bounce.x_end = (wd->size.nw - rw) / 2; + wd->gzoom.bounce.y_end = (wd->size.nh - rh) / 2; + } + else + { + int xx, yy; + + xx = (wd->zoom_point_x / wd->zoom) - wd->pvx; + yy = (wd->zoom_point_y / wd->zoom) - wd->pvy; + + if (xx < 0) xx = 0; + if (yy < 0) yy = 0; + + if (rw > wd->size.nw) + wd->gzoom.bounce.x_end = (wd->size.nw -rw) / 2; + if ((xx + rw) > wd->size.nw) + xx = wd->size.nw - rw; + + if (rh > wd->size.nh) + wd->gzoom.bounce.y_end = (wd->size.nh - rh) / 2; + if ((yy + rh) > wd->size.nh) + yy = wd->size.nh - rh; + + wd->size.spos.x = (double)(xx + (rw / 2)) / (double)(wd->size.nw); + wd->size.spos.y = (double)(yy + (rh / 2)) / (double)(wd->size.nh); + } + + wd->gzoom.bounce.t_start = t; + wd->gzoom.bounce.t_end = t + _elm_config->page_scroll_friction; + + wd->gzoom.bounce.animator = ecore_animator_add(_bounce_eval, wd); + } + else + { + _freeze_off(NULL, wd->obj, NULL); + wd->zoom_gest = EINA_FALSE; + } + + return EVAS_EVENT_FLAG_NONE; } -/** - * Add a new Photocam object - * - * @param parent The parent object - * @return The new object or NULL if it cannot be created - * - * @ingroup Photocam - */ EAPI Evas_Object * elm_photocam_add(Evas_Object *parent) { @@ -955,16 +1324,19 @@ elm_photocam_add(Evas_Object *parent) Widget_Data *wd; Evas_Coord minw, minh; static Evas_Smart *smart = NULL; + Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable; + + ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL); - wd = ELM_NEW(Widget_Data); - e = evas_object_evas_get(parent); - obj = elm_widget_add(e); ELM_SET_WIDTYPE(widtype, "photocam"); elm_widget_type_set(obj, "photocam"); elm_widget_sub_object_add(parent, obj); + elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL); elm_widget_data_set(obj, wd); elm_widget_del_hook_set(obj, _del_hook); elm_widget_theme_hook_set(obj, _theme_hook); + elm_widget_can_focus_set(obj, EINA_TRUE); + elm_widget_event_hook_set(obj, _event_hook); wd->scr = elm_smart_scroller_add(e); elm_smart_scroller_widget_set(wd->scr, obj); @@ -978,8 +1350,8 @@ elm_photocam_add(Evas_Object *parent) evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj); evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj); evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj); - - elm_smart_scroller_bounce_allow_set(wd->scr, 1, 1); + + elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce); wd->obj = obj; @@ -987,39 +1359,41 @@ elm_photocam_add(Evas_Object *parent) evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj); evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj); evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj); - + if (!smart) { - static Evas_Smart_Class sc; - - evas_object_smart_clipped_smart_set(&_pan_sc); - sc = _pan_sc; - sc.name = "elm_photocam_pan"; - sc.version = EVAS_SMART_CLASS_VERSION; - sc.add = _pan_add; - sc.del = _pan_del; - sc.resize = _pan_resize; - sc.move = _pan_move; - sc.calculate = _pan_calculate; - smart = evas_smart_class_new(&sc); + static Evas_Smart_Class sc; + + evas_object_smart_clipped_smart_set(&_pan_sc); + sc = _pan_sc; + sc.name = "elm_photocam_pan"; + sc.version = EVAS_SMART_CLASS_VERSION; + sc.add = _pan_add; + sc.del = _pan_del; + sc.resize = _pan_resize; + sc.move = _pan_move; + sc.calculate = _pan_calculate; + smart = evas_smart_class_new(&sc); } if (smart) { - wd->pan_smart = evas_object_smart_add(e, smart); - wd->pan = evas_object_smart_data_get(wd->pan_smart); - wd->pan->wd = wd; + wd->pan_smart = evas_object_smart_add(e, smart); + wd->pan = evas_object_smart_data_get(wd->pan_smart); + wd->pan->wd = wd; } elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart, - _pan_set, _pan_get, - _pan_max_get, _pan_child_size_get); + _pan_set, _pan_get, _pan_max_get, + _pan_min_get, _pan_child_size_get); + wd->zoom_gest = EINA_FALSE; + wd->gest_start = 1.0; wd->zoom = 1; wd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL; - wd->tsize = 512; - + wd->img = evas_object_image_add(e); + evas_object_image_load_orientation_set(wd->img, EINA_TRUE); evas_object_image_scale_hint_set(wd->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC); evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj); @@ -1033,49 +1407,43 @@ elm_photocam_add(Evas_Object *parent) evas_object_image_filled_set(wd->img, 1); evas_object_event_callback_add(wd->img, EVAS_CALLBACK_IMAGE_PRELOADED, _main_preloaded, obj); - - edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), + + edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh); evas_object_size_hint_min_set(obj, minw, minh); + evas_object_smart_callbacks_descriptions_set(obj, _signals); + _sizing_eval(obj); return obj; } -/** - * Set the photo file to be shown - * - * This sets (and shows) the specified file (with a relative or absolute path) - * and will return a load error (same error that - * evas_object_image_load_error_get() will return). The image will change and - * adjust its size at this point and begin a background load process for this - * photo that at some time in the future will be displayed at the full quality - * needed. - * - * @param obj The photocam object - * @param file The photo file - * @return The return error (see EVAS_LOAD_ERROR_NONE, EVAS_LOAD_ERROR_GENERIC etc.) - * - * @ingroup Photocam - */ -EAPI int +EAPI Evas_Load_Error elm_photocam_file_set(Evas_Object *obj, const char *file) { - ELM_CHECK_WIDTYPE(obj, widtype) 0; + ELM_CHECK_WIDTYPE(obj, widtype) EVAS_LOAD_ERROR_NONE; Widget_Data *wd = elm_widget_data_get(obj); int w, h; if (!wd) return EVAS_LOAD_ERROR_GENERIC; if (!eina_stringshare_replace(&wd->file, file)) return EVAS_LOAD_ERROR_NONE; + grid_clearall(obj); + evas_object_hide(wd->img); evas_object_image_smooth_scale_set(wd->img, (wd->nosmooth == 0)); evas_object_image_file_set(wd->img, NULL, NULL); evas_object_image_load_scale_down_set(wd->img, 0); evas_object_image_file_set(wd->img, wd->file, NULL); evas_object_image_size_get(wd->img, &w, &h); + wd->do_region = evas_object_image_region_support_get(wd->img); wd->size.imw = w; wd->size.imh = h; wd->size.w = wd->size.imw / wd->zoom; wd->size.h = wd->size.imh / wd->zoom; + if (wd->gzoom.bounce.animator) + { + ecore_animator_del(wd->gzoom.bounce.animator); + wd->gzoom.bounce.animator = NULL; + } if (wd->zoom_animator) { wd->nosmooth--; @@ -1088,33 +1456,24 @@ elm_photocam_file_set(Evas_Object *obj, const char *file) evas_object_image_file_set(wd->img, wd->file, NULL); evas_object_image_preload(wd->img, 0); wd->main_load_pending = 1; - grid_clearall(obj); if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); - evas_object_smart_callback_call(obj, "load", NULL); + evas_object_smart_callback_call(obj, SIG_LOAD, NULL); wd->preload_num++; if (wd->preload_num == 1) { edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,start", "elm"); - evas_object_smart_callback_call(obj, "load,detail", NULL); - } - { - double tz = wd->zoom; - wd->zoom = 0.0; - elm_photocam_zoom_set(wd->obj, tz); + evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL); } + { + double tz = wd->zoom; + wd->zoom = 0.0; + elm_photocam_zoom_set(wd->obj, tz); + } return evas_object_image_load_error_get(wd->img); } -/* - * Returns the path of the current image file - * - * @param obj The photocam object - * @return Returns the path - * - * @ingroup Photocam - */ EAPI const char * elm_photocam_file_get(const Evas_Object *obj) { @@ -1124,20 +1483,6 @@ elm_photocam_file_get(const Evas_Object *obj) return wd->file; } -/** - * Set the zoom level of the photo - * - * This sets the zoom level. 1 will be 1:1 pixel for pixel. 2 will be 2:1 - * (that is 2x2 photo pixels will display as 1 on-screen pixel). 4:1 will be - * 4x4 photo pixels as 1 screen pixel, and so on. The @p zoom parameter must - * be greater than 0. It is usggested to stick to powers of 2. (1, 2, 4, 8, - * 16, 32, etc.). - * - * @param obj The photocam object - * @param zoom The zoom level to set - * - * @ingroup Photocam - */ EAPI void elm_photocam_zoom_set(Evas_Object *obj, double zoom) { @@ -1146,7 +1491,7 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) Eina_List *l; Grid *g, *g_zoom = NULL; Evas_Coord pw, ph, rx, ry, rw, rh; - int z; + double z; int zoom_changed = 0, started = 0; Ecore_Animator *an; if (!wd) return; @@ -1169,7 +1514,7 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) if ((wd->size.imw < 1) || (wd->size.imh < 1)) { wd->size.nw = 0; - wd->size.nw = 0; + wd->size.nh = 0; } else { @@ -1184,14 +1529,11 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) pw = rw; } if (wd->size.imw > wd->size.imh) - z = wd->size.imw / pw; + z = (double)wd->size.imw / pw; else - z = wd->size.imh / ph; - if (z >= 8) z = 8; - else if (z >= 4) z = 4; - else if (z >= 2) z = 2; - else z = 1; - if (z != wd->zoom) zoom_changed = 1; + z = (double)wd->size.imh / ph; + if (z != wd->zoom) + zoom_changed = 1; wd->zoom = z; wd->size.nw = pw; wd->size.nh = ph; @@ -1217,14 +1559,46 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) pw = rw; } if (wd->size.imw > wd->size.imh) - z = wd->size.imw / pw; + z = (double)wd->size.imw / pw; + else + z = (double)wd->size.imh / ph; + if (z != wd->zoom) + zoom_changed = 1; + wd->zoom = z; + wd->size.nw = pw; + wd->size.nh = ph; + } + } + else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT_IN) + { + if ((wd->size.imw < 1) || (wd->size.imh < 1)) + { + wd->size.nw = 0; + wd->size.nh = 0; + } + else if ((wd->size.imw < rw) && (wd->size.imh < rh)) + { + if (1 != wd->zoom) zoom_changed = 1; + wd->zoom = 1; + wd->size.nw = wd->size.imw; + wd->size.nh = wd->size.imh; + } + else + { + ph = (wd->size.imh * rw) / wd->size.imw; + if (ph > rh) + { + pw = (wd->size.imw * rh) / wd->size.imh; + ph = rh; + } + else + pw = rw; + if (wd->size.imw > wd->size.imh) + z = (double)wd->size.imw / pw; else - z = wd->size.imh / ph; - if (z >= 8) z = 8; - else if (z >= 4) z = 4; - else if (z >= 2) z = 2; - else z = 1; - if (z != wd->zoom) zoom_changed = 1; + z = (double)wd->size.imh / ph; + if (z != wd->zoom) + zoom_changed = 1; wd->zoom = z; wd->size.nw = pw; wd->size.nh = ph; @@ -1270,7 +1644,7 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) free(g); } } - done: + done: wd->t_start = ecore_loop_time_get(); wd->t_end = wd->t_start + _elm_config->zoom_friction; if ((wd->size.w > 0) && (wd->size.h > 0)) @@ -1315,27 +1689,14 @@ elm_photocam_zoom_set(Evas_Object *obj, double zoom) if (!wd->paused) { if (started) - evas_object_smart_callback_call(obj, "zoom,start", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL); if (!an) - evas_object_smart_callback_call(obj, "zoom,stop", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL); } if (zoom_changed) - evas_object_smart_callback_call(obj, "zoom,change", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL); } -/** - * Get the zoom level of the photo - * - * This returns the current zoom level of the photocam object. Note that if - * you set the fill mode to other than ELM_PHOTOCAM_ZOOM_MODE_MANUAL - * (which is the default), the zoom level may be changed at any time by the - * photocam object itself to account for photo size and photocam viewpoer size - * - * @param obj The photocam object - * @return The current zoom level - * - * @ingroup Photocam - */ EAPI double elm_photocam_zoom_get(const Evas_Object *obj) { @@ -1345,24 +1706,6 @@ elm_photocam_zoom_get(const Evas_Object *obj) return wd->zoom; } -/** - * Set the zoom mode - * - * This sets the zoom mode to manual or one of several automatic levels. - * Manual (ELM_PHOTOCAM_ZOOM_MODE_MANUAL) means that zoom is set manually by - * elm_photocam_zoom_set() and will stay at that level until changed by code - * or until zoom mode is changed. This is the default mode. - * The Automatic modes will allow the photocam object to automatically - * adjust zoom mode based on properties. ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT) will - * adjust zoom so the photo fits EXACTLY inside the scroll frame with no pixels - * outside this area. ELM_PHOTOCAM_ZOOM_MODE_AUTO_FILL will be similar but - * ensure no pixels within the frame are left unfilled. - * - * @param obj The photocam object - * @param mode The desired mode - * - * @ingroup Photocam - */ EAPI void elm_photocam_zoom_mode_set(Evas_Object *obj, Elm_Photocam_Zoom_Mode mode) { @@ -1371,23 +1714,13 @@ elm_photocam_zoom_mode_set(Evas_Object *obj, Elm_Photocam_Zoom_Mode mode) if (!wd) return; if (wd->mode == mode) return; wd->mode = mode; - { - double tz = wd->zoom; - wd->zoom = 0.0; - elm_photocam_zoom_set(wd->obj, tz); - } + { + double tz = wd->zoom; + wd->zoom = 0.0; + elm_photocam_zoom_set(wd->obj, tz); + } } -/** - * Get the zoom mode - * - * This gets the current zoom mode of the photocam object - * - * @param obj The photocam object - * @return The current zoom mode - * - * @ingroup Photocam - */ EAPI Elm_Photocam_Zoom_Mode elm_photocam_zoom_mode_get(const Evas_Object *obj) { @@ -1397,19 +1730,6 @@ elm_photocam_zoom_mode_get(const Evas_Object *obj) return wd->mode; } -/** - * Get the current image pixel width and height - * - * This gets the current photo pixel width and height (for the original). - * The size will be returned in the integers @p w and @p h that are pointed - * to. - * - * @param obj The photocam object - * @param w A pointer to the width return - * @param h A pointer to the height return - * - * @ingroup Photocam - */ EAPI void elm_photocam_image_size_get(const Evas_Object *obj, int *w, int *h) { @@ -1420,14 +1740,8 @@ elm_photocam_image_size_get(const Evas_Object *obj, int *w, int *h) if (h) *h = wd->size.imh; } -/** - * Get the current area of the image that is currently shown - * - * This gets the region - * - */ EAPI void -elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) +elm_photocam_image_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); @@ -1441,7 +1755,6 @@ elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) { *x = (wd->size.imw * sx) / wd->size.w; if (*x > wd->size.imw) *x = wd->size.imw; - else if (*x < 0) *x = 0; } if (w) { @@ -1452,8 +1765,8 @@ elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) } else { - if (x) *x = 0; - if (w) *w = 0; + if (x) *x = 0; + if (w) *w = 0; } if (wd->size.h > 0) @@ -1462,7 +1775,6 @@ elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) { *y = (wd->size.imh * sy) / wd->size.h; if (*y > wd->size.imh) *y = wd->size.imh; - else if (*y < 0) *y = 0; } if (h) { @@ -1473,24 +1785,11 @@ elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) } else { - if (y) *y = 0; - if (h) *h = 0; + if (y) *y = 0; + if (h) *h = 0; } } -/** - * Set the viewed portion of the image - * - * This sets the region of the image to be viewed - * - * @param obj The photocam object - * @param x X-coordinate of region in image original pixels - * @param y Y-coordinate of region in image original pixels - * @param w Width of region in image original pixels - * @param h Height of region in image original pixels - * - * @ingroup Photocam - */ EAPI void elm_photocam_image_region_show(Evas_Object *obj, int x, int y, int w, int h __UNUSED__) { @@ -1502,35 +1801,28 @@ elm_photocam_image_region_show(Evas_Object *obj, int x, int y, int w, int h __UN rx = (x * wd->size.w) / wd->size.imw; ry = (y * wd->size.h) / wd->size.imh; rw = (w * wd->size.w) / wd->size.imw; - rh = (w * wd->size.h) / wd->size.imh; + rh = (h * wd->size.h) / wd->size.imh; if (rw < 1) rw = 1; if (rh < 1) rh = 1; - if ((rx + rw) > wd->size.w) rx = wd->size.w - rw; + if ((rx + rw) > wd->size.w) rx = wd->size.w - rw; if ((ry + rh) > wd->size.h) ry = wd->size.h - rh; + if (wd->gzoom.bounce.animator) + { + ecore_animator_del(wd->gzoom.bounce.animator); + wd->gzoom.bounce.animator = NULL; + zoom_do(obj, 1.0); + } if (wd->zoom_animator) { wd->nosmooth--; ecore_animator_del(wd->zoom_animator); wd->zoom_animator = NULL; zoom_do(obj, 1.0); - evas_object_smart_callback_call(obj, "zoom,stop", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL); } elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh); } -/** - * Bring in the viewed portion of the image - * - * This brings in the region of the image over time - * - * @param obj The photocam object - * @param x X-coordinate of region in image original pixels - * @param y Y-coordinate of region in image original pixels - * @param w Width of region in image original pixels - * @param h Height of region in image original pixels - * - * @ingroup Photocam - */ EAPI void elm_photocam_image_region_bring_in(Evas_Object *obj, int x, int y, int w, int h __UNUSED__) { @@ -1542,35 +1834,29 @@ elm_photocam_image_region_bring_in(Evas_Object *obj, int x, int y, int w, int h rx = (x * wd->size.w) / wd->size.imw; ry = (y * wd->size.h) / wd->size.imh; rw = (w * wd->size.w) / wd->size.imw; - rh = (w * wd->size.h) / wd->size.imh; + rh = (h * wd->size.h) / wd->size.imh; if (rw < 1) rw = 1; if (rh < 1) rh = 1; - if ((rx + rw) > wd->size.w) rx = wd->size.w - rw; + if ((rx + rw) > wd->size.w) rx = wd->size.w - rw; if ((ry + rh) > wd->size.h) ry = wd->size.h - rh; + if (wd->gzoom.bounce.animator) + { + ecore_animator_del(wd->gzoom.bounce.animator); + wd->gzoom.bounce.animator = NULL; + zoom_do(obj, 1.0); + } if (wd->zoom_animator) { wd->nosmooth--; - if (wd->nosmooth == 0) _smooth_update(obj); + if (!wd->nosmooth) _smooth_update(obj); ecore_animator_del(wd->zoom_animator); wd->zoom_animator = NULL; zoom_do(obj, 1.0); - evas_object_smart_callback_call(obj, "zoom,stop", NULL); - } + evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL); + } elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh); } -/** - * Set the paused state for photocam - * - * This sets the paused state to on (1) or off (0) for photocam. The default - * is on. This will stop zooming using animation ch change zoom levels and - * change instantly. This will stop any existing animations that are running. - * - * @param obj The photocam object - * @param paused The pause state to set - * - * @ingroup Photocam - */ EAPI void elm_photocam_paused_set(Evas_Object *obj, Eina_Bool paused) { @@ -1581,26 +1867,22 @@ elm_photocam_paused_set(Evas_Object *obj, Eina_Bool paused) wd->paused = paused; if (wd->paused) { + if (wd->gzoom.bounce.animator) + { + ecore_animator_del(wd->gzoom.bounce.animator); + wd->gzoom.bounce.animator = NULL; + zoom_do(obj, 1.0); + } if (wd->zoom_animator) { ecore_animator_del(wd->zoom_animator); wd->zoom_animator = NULL; zoom_do(obj, 1.0); - evas_object_smart_callback_call(obj, "zoom,stop", NULL); + evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL); } } } -/** - * Get the paused state for photocam - * - * This gets the current paused state for the photocam object. - * - * @param obj The photocam object - * @return The current paused state - * - * @ingroup Photocam - */ EAPI Eina_Bool elm_photocam_paused_get(const Evas_Object *obj) { @@ -1610,18 +1892,6 @@ elm_photocam_paused_get(const Evas_Object *obj) return wd->paused; } -/** - * Get ther internal low-res image used for photocam - * - * This gets the internal image object inside photocam. Do not modify it. It - * is for inspection only, and hooking callbacks to. Nothing else. It may be - * deleted at any time as well. - * - * @param obj The photocam object - * @return The internal image object handle, or NULL if none exists - * - * @ingroup Photocam - */ EAPI Evas_Object * elm_photocam_internal_image_get(const Evas_Object *obj) { @@ -1630,3 +1900,63 @@ elm_photocam_internal_image_get(const Evas_Object *obj) if (!wd) return NULL; return wd->img; } + +EAPI void +elm_photocam_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce); +} + +EAPI void +elm_photocam_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce); +} + +EAPI void +elm_photocam_gesture_enabled_set(Evas_Object *obj, Eina_Bool gesture) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + if (wd->do_gesture == !!gesture) return; + + if (wd->gest) + { + evas_object_del(wd->gest); + wd->gest = NULL; + } + + if (gesture) + { + wd->gest = elm_gesture_layer_add(wd->obj); + if (!wd->gest) return; + elm_gesture_layer_attach(wd->gest, wd->obj); + elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_START, + _gzoom_start, wd); + elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_MOVE, + _gzoom_move, wd); + elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_END, + _gzoom_end, wd); + elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_ABORT, + _gzoom_end, wd); + } + + wd->do_gesture = !!gesture; +} + +EAPI Eina_Bool +elm_photocam_gesture_enabled_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return EINA_FALSE; + + return wd->do_gesture; +}