[multibuttenentry] merged with opensource r75453.
[framework/uifw/elementary.git] / src / lib / elm_photocam.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "els_scroller.h"
4
5 /*
6  * TODO (maybe - optional future stuff):
7  *
8  * 1. wrap photo in theme edje so u can have styling around photo (like white
9  *    photo bordering).
10  * 2. exif handling
11  * 3. rotation flags in exif handling (nasty! should have rot in evas)
12  */
13
14 typedef struct _Widget_Data Widget_Data;
15 typedef struct _Pan Pan;
16 typedef struct _Grid Grid;
17 typedef struct _Grid_Item Grid_Item;
18
19 struct _Grid_Item
20 {
21    Widget_Data *wd;
22    Evas_Object *img;
23    struct
24    {
25       int x, y, w, h;
26    } src, out;
27    Eina_Bool want : 1;
28    Eina_Bool have : 1;
29 };
30
31 struct _Grid
32 {
33    int tsize; // size of tile (tsize x tsize pixels)
34    int zoom; // zoom level tiles want for optimal display (1, 2, 4, 8)
35    int iw, ih; // size of image in pixels
36    int w, h; // size of grid image in pixels (represented by grid)
37    int gw, gh; // size of grid in tiles
38    Grid_Item *grid; // the grid (gw * gh items)
39    Eina_Bool dead : 1; // old grid. will die as soon as anim is over
40 };
41
42 struct _Widget_Data
43 {
44    Evas_Object *obj;
45    Evas_Object *scr;
46    Evas_Object *pan_smart;
47    Evas_Object *gest;
48    double       gest_start;
49
50    Pan *pan;
51    Evas_Coord pan_x, pan_y, minw, minh;
52
53    double zoom;
54    Elm_Photocam_Zoom_Mode mode;
55    Evas_Coord pvx, pvy, px, py, zoom_point_x, zoom_point_y;
56    struct
57    {
58       int imx, imy;
59       struct
60       {
61          int x_start, y_start;
62          int x_end, y_end;
63          double t_start;
64          double t_end;
65          Ecore_Animator *animator;
66       } bounce;
67    } gzoom;
68    const char *file;
69
70    Ecore_Job *calc_job;
71    Ecore_Timer *scr_timer;
72    Ecore_Timer *long_timer;
73    Ecore_Animator *zoom_animator;
74    double t_start, t_end;
75    struct
76    {
77       int imw, imh;
78       int w, h;
79       int ow, oh, nw, nh;
80       struct
81       {
82          double x, y;
83       } spos;
84    } size;
85    struct
86    {
87       Eina_Bool show : 1;
88       Evas_Coord x, y ,w ,h;
89    } show;
90    int tsize;
91    Evas_Object *img; // low res version of image (scale down == 8)
92    int nosmooth;
93    int preload_num;
94    Eina_List *grids;
95    Eina_Bool main_load_pending : 1;
96    Eina_Bool resized : 1;
97    Eina_Bool longpressed : 1;
98    Eina_Bool on_hold : 1;
99    Eina_Bool paused : 1;
100    Eina_Bool do_region : 1;
101    Eina_Bool do_gesture : 1;
102    Eina_Bool zoom_gest : 1;
103 };
104
105 struct _Pan
106 {
107    Evas_Object_Smart_Clipped_Data __clipped_data;
108    Widget_Data *wd;
109 };
110
111 static const char *widtype = NULL;
112 static void _del_hook(Evas_Object *obj);
113 static void _theme_hook(Evas_Object *obj);
114 static void _on_focus_hook(void *data, Evas_Object *obj);
115 //static void _show_region_hook(void *data, Evas_Object *obj);
116 static void _sizing_eval(Evas_Object *obj);
117 static void _calc_job(void *data);
118 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__,
119                              Evas_Callback_Type type, void *event_info);
120 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);
121 static void grid_clear(Evas_Object *obj, Grid *g);
122 static Grid *grid_create(Evas_Object *obj);
123 static void grid_load(Evas_Object *obj, Grid *g);
124
125 static const char SIG_CLICKED[] = "clicked";
126 static const char SIG_PRESS[] = "press";
127 static const char SIG_LONGPRESSED[] = "longpressed";
128 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
129 static const char SIG_LOAD[] = "load";
130 static const char SIG_LOADED[] = "loaded";
131 static const char SIG_LOAD_DETAIL[] = "load,detail";
132 static const char SIG_LOADED_DETAIL[] = "loaded,detail";
133 static const char SIG_ZOOM_START[] = "zoom,start";
134 static const char SIG_ZOOM_STOP[] = "zoom,stop";
135 static const char SIG_ZOOM_CHANGE[] = "zoom,change";
136 static const char SIG_SCROLL[] = "scroll";
137 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
138 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
139 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
140 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
141
142 static const Evas_Smart_Cb_Description _signals[] = {
143    {SIG_CLICKED, ""},
144    {SIG_PRESS, ""},
145    {SIG_LONGPRESSED, ""},
146    {SIG_CLICKED_DOUBLE, ""},
147    {SIG_LOAD, ""},
148    {SIG_LOADED, ""},
149    {SIG_LOAD_DETAIL, ""},
150    {SIG_LOADED_DETAIL, ""},
151    {SIG_ZOOM_START, ""},
152    {SIG_ZOOM_STOP, ""},
153    {SIG_ZOOM_CHANGE, ""},
154    {SIG_SCROLL, ""},
155    {SIG_SCROLL_ANIM_START, ""},
156    {SIG_SCROLL_ANIM_STOP, ""},
157    {SIG_SCROLL_DRAG_START, ""},
158    {SIG_SCROLL_DRAG_STOP, ""},
159    {NULL, NULL}
160 };
161
162
163 static int
164 nearest_pow2(int num)
165 {
166    unsigned int n = num - 1;
167    n |= n >> 1;
168    n |= n >> 2;
169    n |= n >> 4;
170    n |= n >> 8;
171    n |= n >> 16;
172    return n + 1;
173 }
174
175 static void
176 img_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
177 {
178    Widget_Data *wd = elm_widget_data_get(obj);
179    Evas_Coord ax, ay, gw, gh;
180    if (!wd) return;
181    ax = 0;
182    ay = 0;
183    gw = wd->size.w;
184    gh = wd->size.h;
185    if (!wd->zoom_gest)
186      {
187         if (ow > gw) ax = (ow - gw) / 2;
188         if (oh > gh) ay = (oh - gh) / 2;
189      }
190    evas_object_move(wd->img, ox + 0 - px + ax, oy + 0 - py + ay);
191    evas_object_resize(wd->img, gw, gh);
192
193    if (wd->show.show)
194      {
195         wd->show.show = EINA_FALSE;
196         elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h);
197      }
198 }
199
200 static void
201 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)
202 {
203    Widget_Data *wd = elm_widget_data_get(obj);
204    Evas_Coord ax, ay, gw, gh, tx, ty;
205    int x, y;
206    if (!wd) return;
207    ax = 0;
208    ay = 0;
209    gw = wd->size.w;
210    gh = wd->size.h;
211    if (!wd->zoom_gest)
212      {
213         if (ow > gw) ax = (ow - gw) / 2;
214         if (oh > gh) ay = (oh - gh) / 2;
215      }
216    for (y = 0; y < g->gh; y++)
217      {
218         for (x = 0; x < g->gw; x++)
219           {
220              int tn, xx, yy, ww, hh;
221
222              tn = (y * g->gw) + x;
223              xx = g->grid[tn].out.x;
224              yy = g->grid[tn].out.y;
225              ww = g->grid[tn].out.w;
226              hh = g->grid[tn].out.h;
227              if ((gw != g->w) && (g->w > 0))
228                {
229                   tx = xx;
230                   xx = (gw * xx) / g->w;
231                   ww = ((gw * (tx + ww)) / g->w) - xx;
232                }
233              if ((gh != g->h) && (g->h > 0))
234                {
235                   ty = yy;
236                   yy = (gh * yy) / g->h;
237                   hh = ((gh * (ty + hh)) / g->h) - yy;
238                }
239              evas_object_move(g->grid[tn].img,
240                               ox + xx - px + ax,
241                               oy + yy - py + ay);
242              evas_object_resize(g->grid[tn].img, ww, hh);
243           }
244      }
245 }
246
247 static void
248 grid_clear(Evas_Object *obj, Grid *g)
249 {
250    Widget_Data *wd = elm_widget_data_get(obj);
251    int x, y;
252    if (!wd) return;
253    if (!g->grid) return;
254    for (y = 0; y < g->gh; y++)
255      {
256         for (x = 0; x < g->gw; x++)
257           {
258              int tn;
259
260              tn = (y * g->gw) + x;
261              evas_object_del(g->grid[tn].img);
262              if (g->grid[tn].want)
263                {
264                   wd->preload_num--;
265                   if (!wd->preload_num)
266                     {
267                        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
268                                                "elm,state,busy,stop", "elm");
269                        evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
270                     }
271                }
272           }
273      }
274    free(g->grid);
275    g->grid = NULL;
276    g->gw = 0;
277    g->gh = 0;
278 }
279
280 static void
281 _tile_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
282 {
283    Grid_Item *git = data;
284
285    if (git->want)
286      {
287         git->want = 0;
288         evas_object_show(git->img);
289         git->have = 1;
290         git->wd->preload_num--;
291         if (!git->wd->preload_num)
292           {
293              edje_object_signal_emit(elm_smart_scroller_edje_object_get(git->wd->scr),
294                                      "elm,state,busy,stop", "elm");
295              evas_object_smart_callback_call(git->wd->obj, SIG_LOADED_DETAIL, NULL);
296           }
297      }
298 }
299
300 static int
301 grid_zoom_calc(double zoom)
302 {
303    int z = zoom;
304    if (z < 1) z = 1;
305    return nearest_pow2(z);
306 }
307
308 static Grid *
309 grid_create(Evas_Object *obj)
310 {
311    Widget_Data *wd = elm_widget_data_get(obj);
312    int x, y;
313    Grid *g;
314
315    if (!wd) return NULL;
316    g = calloc(1, sizeof(Grid));
317    if (!g) return NULL;
318
319    g->zoom = grid_zoom_calc(wd->zoom);
320    g->tsize = wd->tsize;
321    g->iw = wd->size.imw;
322    g->ih = wd->size.imh;
323
324    g->w = g->iw / g->zoom;
325    g->h = g->ih / g->zoom;
326    if (g->zoom >= 8)
327      {
328         free(g);
329         return NULL;
330      }
331    if (wd->do_region)
332      {
333         g->gw = (g->w + g->tsize - 1) / g->tsize;
334         g->gh = (g->h + g->tsize - 1) / g->tsize;
335      }
336    else
337      {
338         g->gw = 1;
339         g->gh = 1;
340      }
341    g->grid = calloc(1, sizeof(Grid_Item) * g->gw * g->gh);
342    if (!g->grid)
343      {
344         g->gw = 0;
345         g->gh = 0;
346         return g;
347      }
348    for (y = 0; y < g->gh; y++)
349      {
350         for (x = 0; x < g->gw; x++)
351           {
352              int tn;
353
354              tn = (y * g->gw) + x;
355              g->grid[tn].src.x = x * g->tsize;
356              if (x == (g->gw - 1))
357                g->grid[tn].src.w = g->w - ((g->gw - 1) * g->tsize);
358              else
359                g->grid[tn].src.w = g->tsize;
360              g->grid[tn].src.y = y * g->tsize;
361              if (y == (g->gh - 1))
362                g->grid[tn].src.h = g->h - ((g->gh - 1) * g->tsize);
363              else
364                g->grid[tn].src.h = g->tsize;
365
366              g->grid[tn].out.x = g->grid[tn].src.x;
367              g->grid[tn].out.y = g->grid[tn].src.y;
368              g->grid[tn].out.w = g->grid[tn].src.w;
369              g->grid[tn].out.h = g->grid[tn].src.h;
370
371              g->grid[tn].wd = wd;
372              g->grid[tn].img =
373                 evas_object_image_add(evas_object_evas_get(obj));
374              evas_object_image_load_orientation_set(g->grid[tn].img, EINA_TRUE);
375              evas_object_image_scale_hint_set
376                 (g->grid[tn].img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
377              evas_object_pass_events_set(g->grid[tn].img, EINA_TRUE);
378              evas_object_smart_member_add(g->grid[tn].img,
379                                           wd->pan_smart);
380              elm_widget_sub_object_add(obj, g->grid[tn].img);
381              evas_object_image_filled_set(g->grid[tn].img, 1);
382              evas_object_event_callback_add(g->grid[tn].img,
383                                             EVAS_CALLBACK_IMAGE_PRELOADED,
384                                             _tile_preloaded,
385                                             &(g->grid[tn]));
386           }
387      }
388    return g;
389 }
390
391 static void
392 grid_load(Evas_Object *obj, Grid *g)
393 {
394    Widget_Data *wd = elm_widget_data_get(obj);
395    int x, y;
396    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, gw, gh, tx, ty;
397    if (!wd) return;
398    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
399    evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
400    gw = wd->size.w;
401    gh = wd->size.h;
402    for (y = 0; y < g->gh; y++)
403      {
404         for (x = 0; x < g->gw; x++)
405           {
406              int tn, xx, yy, ww, hh;
407              Eina_Bool visible = EINA_FALSE;
408
409              tn = (y * g->gw) + x;
410              xx = g->grid[tn].out.x;
411              yy = g->grid[tn].out.y;
412              ww = g->grid[tn].out.w;
413              hh = g->grid[tn].out.h;
414              if ((gw != g->w) && (g->w > 0))
415                {
416                   tx = xx;
417                   xx = (gw * xx) / g->w;
418                   ww = ((gw * (tx + ww)) / g->w) - xx;
419                }
420              if ((gh != g->h) && (g->h > 0))
421                {
422                   ty = yy;
423                   yy = (gh * yy) / g->h;
424                   hh = ((gh * (ty + hh)) / g->h) - yy;
425                }
426              if (ELM_RECTS_INTERSECT(xx - wd->pan_x + ox,
427                                      yy  - wd->pan_y + oy,
428                                      ww, hh,
429                                      cvx, cvy, cvw, cvh))
430                visible = 1;
431              if ((visible) && (!g->grid[tn].have) && (!g->grid[tn].want))
432                {
433                   g->grid[tn].want = 1;
434                   evas_object_hide(g->grid[tn].img);
435                   evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
436                   evas_object_image_load_scale_down_set(g->grid[tn].img, g->zoom);
437                   evas_object_image_load_region_set(g->grid[tn].img,
438                                                     g->grid[tn].src.x,
439                                                     g->grid[tn].src.y,
440                                                     g->grid[tn].src.w,
441                                                     g->grid[tn].src.h);
442                   evas_object_image_file_set(g->grid[tn].img, wd->file, NULL);
443                   evas_object_image_preload(g->grid[tn].img, 0);
444                   wd->preload_num++;
445                   if (wd->preload_num == 1)
446                     {
447                        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
448                                                "elm,state,busy,start", "elm");
449                        evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
450                     }
451                }
452              else if ((g->grid[tn].want) && (!visible))
453                {
454                   wd->preload_num--;
455                   if (!wd->preload_num)
456                     {
457                        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
458                                                "elm,state,busy,stop", "elm");
459                        evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
460                     }
461                   g->grid[tn].want = 0;
462                   evas_object_hide(g->grid[tn].img);
463                   evas_object_image_preload(g->grid[tn].img, 1);
464                   evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
465                }
466              else if ((g->grid[tn].have) && (!visible))
467                {
468                   g->grid[tn].have = 0;
469                   evas_object_hide(g->grid[tn].img);
470                   evas_object_image_preload(g->grid[tn].img, 1);
471                   evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
472                }
473           }
474      }
475 }
476
477 static void
478 grid_clearall(Evas_Object *obj)
479 {
480    Widget_Data *wd = elm_widget_data_get(obj);
481    Grid *g;
482    if (!wd) return;
483    EINA_LIST_FREE(wd->grids, g)
484      {
485         grid_clear(obj, g);
486         free(g);
487      }
488 }
489
490 static void
491 _smooth_update(Evas_Object *obj)
492 {
493    Widget_Data *wd = elm_widget_data_get(obj);
494    int x, y;
495    Eina_List *l;
496    Grid *g;
497    if (!wd) return;
498    EINA_LIST_FOREACH(wd->grids, l, g)
499      {
500         for (y = 0; y < g->gh; y++)
501           {
502              for (x = 0; x < g->gw; x++)
503                {
504                   int tn;
505
506                   tn = (y * g->gw) + x;
507                   evas_object_image_smooth_scale_set(g->grid[tn].img, (!wd->nosmooth));
508                }
509           }
510      }
511    evas_object_image_smooth_scale_set(wd->img, (!wd->nosmooth));
512 }
513
514 static void
515 _grid_raise(Grid *g)
516 {
517    int x, y;
518
519    for (y = 0; y < g->gh; y++)
520      {
521         for (x = 0; x < g->gw; x++)
522           {
523              int tn;
524
525              tn = (y * g->gw) + x;
526              evas_object_raise(g->grid[tn].img);
527           }
528      }
529 }
530
531 static Eina_Bool
532 _scr_timeout(void *data)
533 {
534    Widget_Data *wd = elm_widget_data_get(data);
535    if (!wd) return ECORE_CALLBACK_CANCEL;
536    wd->nosmooth--;
537    if (!wd->nosmooth) _smooth_update(data);
538    wd->scr_timer = NULL;
539    return ECORE_CALLBACK_CANCEL;
540 }
541
542 static void
543 _scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
544 {
545    Widget_Data *wd = elm_widget_data_get(data);
546    if (!wd) return;
547    if (!wd->scr_timer)
548      {
549         wd->nosmooth++;
550         if (wd->nosmooth == 1) _smooth_update(data);
551      }
552    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
553    wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
554 }
555
556 static void
557 _main_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
558 {
559    Evas_Object *obj = data;
560    Widget_Data *wd = elm_widget_data_get(obj);
561    Grid *g;
562    if (!wd) return;
563    evas_object_show(wd->img);
564    wd->main_load_pending = 0;
565    g = grid_create(obj);
566    if (g)
567      {
568         wd->grids = eina_list_prepend(wd->grids, g);
569         grid_load(wd->obj, g);
570      }
571    if (wd->calc_job) ecore_job_del(wd->calc_job);
572    wd->calc_job = ecore_job_add(_calc_job, wd);
573    evas_object_smart_callback_call(data, SIG_LOADED, NULL);
574    wd->preload_num--;
575    if (!wd->preload_num)
576      {
577         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
578                                 "elm,state,busy,stop", "elm");
579         evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
580      }
581 }
582
583 static Eina_Bool
584 zoom_do(Evas_Object *obj, double t)
585 {
586    Widget_Data *wd = elm_widget_data_get(obj);
587    Evas_Coord xx, yy, ow, oh;
588    if (!wd) return ECORE_CALLBACK_CANCEL;
589    wd->size.w = (wd->size.ow * (1.0 - t)) + (wd->size.nw * t);
590    wd->size.h = (wd->size.oh * (1.0 - t)) + (wd->size.nh * t);
591    elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
592    xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
593    yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
594    if (xx < 0) xx = 0;
595    else if (xx > (wd->size.w - ow)) xx = wd->size.w - ow;
596    if (yy < 0) yy = 0;
597    else if (yy > (wd->size.h - oh)) yy = wd->size.h - oh;
598
599    wd->show.show = EINA_TRUE;
600    wd->show.x = xx;
601    wd->show.y = yy;
602    wd->show.w = ow;
603    wd->show.h = oh;
604
605    if (wd->calc_job) ecore_job_del(wd->calc_job);
606    wd->calc_job = ecore_job_add(_calc_job, wd);
607    if (t >= 1.0)
608      {
609         Eina_List *l, *l_next;
610         Grid *g;
611
612         EINA_LIST_FOREACH_SAFE(wd->grids, l, l_next, g)
613           {
614              if (g->dead)
615                {
616                   wd->grids = eina_list_remove_list(wd->grids, l);
617                   grid_clear(obj, g);
618                   free(g);
619                }
620           }
621         return ECORE_CALLBACK_CANCEL;
622      }
623    return ECORE_CALLBACK_RENEW;
624 }
625
626
627 static Eina_Bool
628 _zoom_anim(void *data)
629 {
630    Evas_Object *obj = data;
631    Widget_Data *wd = elm_widget_data_get(obj);
632    double t;
633    Eina_Bool go;
634    if (!wd) return ECORE_CALLBACK_CANCEL;
635    t = ecore_loop_time_get();
636    if (t >= wd->t_end)
637      t = 1.0;
638    else if (wd->t_end > wd->t_start)
639      t = (t - wd->t_start) / (wd->t_end - wd->t_start);
640    else
641      t = 1.0;
642    t = 1.0 - t;
643    t = 1.0 - (t * t);
644    go = zoom_do(obj, t);
645    if (!go)
646      {
647         wd->nosmooth--;
648         if (!wd->nosmooth) _smooth_update(data);
649         wd->zoom_animator = NULL;
650         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
651      }
652    return go;
653 }
654
655 static void
656 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
657 {
658    Widget_Data *wd = elm_widget_data_get(data);
659    //   Evas_Event_Mouse_Move *ev = event_info;
660    if (!wd) return;
661 }
662
663 static Eina_Bool
664 _long_press(void *data)
665 {
666    Widget_Data *wd = elm_widget_data_get(data);
667    if (!wd) return ECORE_CALLBACK_CANCEL;
668    wd->long_timer = NULL;
669    wd->longpressed = EINA_TRUE;
670    evas_object_smart_callback_call(data, SIG_LONGPRESSED, NULL);
671    return ECORE_CALLBACK_CANCEL;
672 }
673
674 static void
675 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
676 {
677    Widget_Data *wd = elm_widget_data_get(data);
678    Evas_Event_Mouse_Down *ev = event_info;
679    if (!wd) return;
680    if (ev->button != 1) return;
681    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
682    else wd->on_hold = EINA_FALSE;
683    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
684      evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, NULL);
685    else
686      evas_object_smart_callback_call(data, SIG_PRESS, NULL);
687    wd->longpressed = EINA_FALSE;
688    if (wd->long_timer) ecore_timer_del(wd->long_timer);
689    wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data);
690 }
691
692 static void
693 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
694 {
695    Widget_Data *wd = elm_widget_data_get(data);
696    Evas_Event_Mouse_Up *ev = event_info;
697    if (!wd) return;
698    if (ev->button != 1) return;
699    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
700    else wd->on_hold = EINA_FALSE;
701    if (wd->long_timer)
702      {
703         ecore_timer_del(wd->long_timer);
704         wd->long_timer = NULL;
705      }
706    if (!wd->on_hold)
707      evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
708    wd->on_hold = EINA_FALSE;
709 }
710
711 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL;
712
713 static void
714 _del_hook(Evas_Object *obj)
715 {
716    Widget_Data *wd = elm_widget_data_get(obj);
717    Grid *g;
718    if (!wd) return;
719    EINA_LIST_FREE(wd->grids, g)
720      {
721         if (g->grid) free(g->grid);
722         free(g);
723      }
724    evas_object_del(wd->pan_smart);
725    wd->pan_smart = NULL;
726    if (wd->file) eina_stringshare_del(wd->file);
727    if (wd->calc_job) ecore_job_del(wd->calc_job);
728    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
729    if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
730    if (wd->gzoom.bounce.animator) ecore_animator_del(wd->gzoom.bounce.animator);
731    if (wd->long_timer) ecore_timer_del(wd->long_timer);
732    free(wd);
733 }
734
735 static void
736 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
737 {
738    Widget_Data *wd = elm_widget_data_get(obj);
739    if (!wd) return;
740    if (elm_widget_focus_get(obj))
741      {
742         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm");
743         evas_object_focus_set(wd->obj, EINA_TRUE);
744      }
745    else
746      {
747         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm");
748         evas_object_focus_set(wd->obj, EINA_FALSE);
749      }
750 }
751
752 static void
753 _theme_hook(Evas_Object *obj)
754 {
755    Widget_Data *wd = elm_widget_data_get(obj);
756    if (!wd) return;
757    elm_smart_scroller_object_theme_set(obj, wd->scr, "photocam", "base", elm_widget_style_get(obj));
758    //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
759    _sizing_eval(obj);
760 }
761
762 /*
763 static void
764 _show_region_hook(void *data, Evas_Object *obj)
765 {
766    Widget_Data *wd = elm_widget_data_get(data);
767    Evas_Coord x, y, w, h;
768    if (!wd) return;
769    elm_widget_show_region_get(obj, &x, &y, &w, &h);
770    elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
771 }
772 */
773
774 static void
775 _sizing_eval(Evas_Object *obj)
776 {
777    Widget_Data *wd = elm_widget_data_get(obj);
778    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
779    if (!wd) return;
780    //   evas_object_size_hint_min_get(wd->scr, &minw, &minh);
781    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
782    //   minw = -1;
783    //   minh = -1;
784    //   if (wd->mode != ELM_LIST_LIMIT) minw = -1;
785    evas_object_size_hint_min_set(obj, minw, minh);
786    evas_object_size_hint_max_set(obj, maxw, maxh);
787 }
788
789 static void
790 _calc_job(void *data)
791 {
792    Widget_Data *wd = data;
793    Evas_Coord minw, minh;
794    if (!wd) return;
795    minw = wd->size.w;
796    minh = wd->size.h;
797    if (wd->resized)
798      {
799         wd->resized = 0;
800         if (wd->mode != ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
801           {
802              double tz = wd->zoom;
803              wd->zoom = 0.0;
804              elm_photocam_zoom_set(wd->obj, tz);
805           }
806      }
807    if ((minw != wd->minw) || (minh != wd->minh))
808      {
809         wd->minw = minw;
810         wd->minh = minh;
811         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
812         _sizing_eval(wd->obj);
813      }
814    wd->calc_job = NULL;
815    evas_object_smart_changed(wd->pan_smart);
816 }
817
818 static void
819 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
820 {
821    Pan *sd = evas_object_smart_data_get(obj);
822    if (!sd) return;
823    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
824    sd->wd->pan_x = x;
825    sd->wd->pan_y = y;
826    evas_object_smart_changed(obj);
827 }
828
829 static void
830 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
831 {
832    Pan *sd = evas_object_smart_data_get(obj);
833    if (!sd) return;
834    if (x) *x = sd->wd->pan_x;
835    if (y) *y = sd->wd->pan_y;
836 }
837
838 static void
839 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
840 {
841    Pan *sd = evas_object_smart_data_get(obj);
842    Evas_Coord ow, oh;
843    if (!sd) return;
844    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
845    ow = sd->wd->minw - ow;
846    if (ow < 0) ow = 0;
847    oh = sd->wd->minh - oh;
848    if (oh < 0) oh = 0;
849    if (x) *x = ow;
850    if (y) *y = oh;
851 }
852
853 static void
854 _pan_min_get(Evas_Object *obj __UNUSED__, Evas_Coord *x, Evas_Coord *y)
855 {
856    if (x) *x = 0;
857    if (y) *y = 0;
858 }
859
860 static void
861 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
862 {
863    Pan *sd = evas_object_smart_data_get(obj);
864    if (!sd) return;
865    if (w) *w = sd->wd->minw;
866    if (h) *h = sd->wd->minh;
867 }
868
869 static void
870 _pan_add(Evas_Object *obj)
871 {
872    Pan *sd;
873    Evas_Object_Smart_Clipped_Data *cd;
874    _pan_sc.add(obj);
875    cd = evas_object_smart_data_get(obj);
876    if (!cd) return;
877    sd = calloc(1, sizeof(Pan));
878    if (!sd) return;
879    sd->__clipped_data = *cd;
880    free(cd);
881    evas_object_smart_data_set(obj, sd);
882 }
883
884 static void
885 _pan_del(Evas_Object *obj)
886 {
887    Pan *sd = evas_object_smart_data_get(obj);
888    if (!sd) return;
889    _pan_sc.del(obj);
890 }
891
892 static void
893 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
894 {
895    Pan *sd = evas_object_smart_data_get(obj);
896    Evas_Coord ow, oh;
897    if (!sd) return;
898    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
899    if ((ow == w) && (oh == h)) return;
900    sd->wd->resized = 1;
901    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
902    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
903 }
904
905 static void
906 _pan_calculate(Evas_Object *obj)
907 {
908    Pan *sd = evas_object_smart_data_get(obj);
909    Evas_Coord ox, oy, ow, oh;
910    Eina_List *l;
911    Grid *g;
912    if (!sd) return;
913    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
914    img_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y,
915              ox - sd->wd->gzoom.imx, oy - sd->wd->gzoom.imy, ow, oh);
916    EINA_LIST_FOREACH(sd->wd->grids, l, g)
917      {
918         grid_load(sd->wd->obj, g);
919         grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y,
920                    ox - sd->wd->gzoom.imx, oy - sd->wd->gzoom.imy, ow, oh);
921      }
922 }
923
924 static void
925 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
926 {
927    Pan *sd = evas_object_smart_data_get(obj);
928    if (!sd) return;
929    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
930    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
931 }
932
933 static void
934 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
935 {
936    Widget_Data *wd = elm_widget_data_get(obj);
937    if (!wd) return;
938    elm_smart_scroller_hold_set(wd->scr, 1);
939 }
940
941 static void
942 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
943 {
944    Widget_Data *wd = elm_widget_data_get(obj);
945    if (!wd) return;
946    elm_smart_scroller_hold_set(wd->scr, 0);
947 }
948
949 static void
950 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
951 {
952    Widget_Data *wd = elm_widget_data_get(obj);
953    if (!wd) return;
954    elm_smart_scroller_freeze_set(wd->scr, 1);
955 }
956
957 static void
958 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
959 {
960    Widget_Data *wd = elm_widget_data_get(obj);
961    if (!wd) return;
962    elm_smart_scroller_freeze_set(wd->scr, 0);
963 }
964
965 static void
966 _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
967 {
968    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
969 }
970
971 static void
972 _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
973 {
974    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
975 }
976
977 static void
978 _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
979 {
980    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
981 }
982
983 static void
984 _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
985 {
986    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
987 }
988
989 static void
990 _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
991 {
992    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
993 }
994
995 static Eina_Bool
996 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__,
997             Evas_Callback_Type type, void *event_info)
998 {
999    double zoom;
1000    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1001    Evas_Event_Key_Down *ev = event_info;
1002    Widget_Data *wd = elm_widget_data_get(obj);
1003    if (!wd) return EINA_FALSE;
1004    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
1005
1006    Evas_Coord x = 0;
1007    Evas_Coord y = 0;
1008    Evas_Coord step_x = 0;
1009    Evas_Coord step_y = 0;
1010    Evas_Coord v_w = 0;
1011    Evas_Coord v_h = 0;
1012    Evas_Coord page_x = 0;
1013    Evas_Coord page_y = 0;
1014
1015    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
1016    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
1017    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
1018    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
1019
1020    if ((!strcmp(ev->keyname, "Left")) ||
1021        ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
1022      {
1023         x -= step_x;
1024      }
1025    else if ((!strcmp(ev->keyname, "Right")) ||
1026             ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
1027      {
1028         x += step_x;
1029      }
1030    else if ((!strcmp(ev->keyname, "Up"))  ||
1031             ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string)))
1032      {
1033         y -= step_y;
1034      }
1035    else if ((!strcmp(ev->keyname, "Down")) ||
1036             ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string)))
1037      {
1038         y += step_y;
1039      }
1040    else if ((!strcmp(ev->keyname, "Prior")) ||
1041             ((!strcmp(ev->keyname, "KP_Prior")) && (!ev->string)))
1042      {
1043         if (page_y < 0)
1044           y -= -(page_y * v_h) / 100;
1045         else
1046           y -= page_y;
1047      }
1048    else if ((!strcmp(ev->keyname, "Next")) ||
1049             ((!strcmp(ev->keyname, "KP_Next")) && (!ev->string)))
1050      {
1051         if (page_y < 0)
1052           y += -(page_y * v_h) / 100;
1053         else
1054           y += page_y;
1055      }
1056    else if ((!strcmp(ev->keyname, "KP_Add")))
1057      {
1058         zoom = elm_photocam_zoom_get(obj);
1059         zoom -= 0.5;
1060         elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL);
1061         elm_photocam_zoom_set(obj, zoom);
1062         return EINA_TRUE;
1063      }
1064    else if ((!strcmp(ev->keyname, "KP_Subtract")))
1065      {
1066         zoom = elm_photocam_zoom_get(obj);
1067         zoom += 0.5;
1068         elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL);
1069         elm_photocam_zoom_set(obj, zoom);
1070         return EINA_TRUE;
1071      }
1072    else return EINA_FALSE;
1073
1074    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1075    elm_smart_scroller_child_pos_set(wd->scr, x, y);
1076
1077    return EINA_TRUE;
1078 }
1079
1080 Eina_Bool
1081 _bounce_eval(void *_wd)
1082 {
1083    Widget_Data *wd = (Widget_Data *)_wd;
1084    double t, tt;
1085
1086    if (!wd) return ECORE_CALLBACK_CANCEL;
1087    if ((wd->gzoom.imx == wd->gzoom.bounce.x_end) &&
1088        (wd->gzoom.imy == wd->gzoom.bounce.y_end))
1089      {
1090         wd->gzoom.imx = 0;
1091         wd->gzoom.imy = 0;
1092         wd->zoom_gest = EINA_FALSE;
1093         wd->gzoom.bounce.animator = NULL;
1094         _freeze_off(NULL, wd->obj, NULL);
1095         return ECORE_CALLBACK_CANCEL;
1096      }
1097
1098    t = ecore_loop_time_get();
1099    tt = (t - wd->gzoom.bounce.t_start) / (wd->gzoom.bounce.t_end - wd->gzoom.bounce.t_start);
1100    tt = 1.0 - tt;
1101    tt = 1.0 - (tt * tt);
1102
1103    if (t > wd->gzoom.bounce.t_end)
1104      {
1105         wd->gzoom.imx = 0;
1106         wd->gzoom.imy = 0;
1107         wd->zoom_gest = EINA_FALSE;
1108         _freeze_off(NULL, wd->obj, NULL);
1109         zoom_do(wd->obj, 1.0);
1110         wd->gzoom.bounce.animator = NULL;
1111         return ECORE_CALLBACK_CANCEL;
1112      }
1113
1114    if (wd->gzoom.imx != wd->gzoom.bounce.x_end)
1115      wd->gzoom.imx = wd->gzoom.bounce.x_start * (1.0 - tt) + wd->gzoom.bounce.x_end * tt;
1116
1117    if (wd->gzoom.imy != wd->gzoom.bounce.y_end)
1118      wd->gzoom.imy = wd->gzoom.bounce.y_start * (1.0 - tt) + wd->gzoom.bounce.y_end * tt;
1119
1120    zoom_do(wd->obj, 1.0 - (1.0 - tt));
1121    return ECORE_CALLBACK_RENEW;
1122 }
1123
1124 static void
1125 _gzoom(Widget_Data *_wd, Evas_Coord px, Evas_Coord py, Elm_Gesture_Zoom_Info* gest)
1126 {
1127    Widget_Data *wd = (Widget_Data *)_wd;
1128    Evas_Coord rx, ry, rw, rh;
1129    int regx, regy, regw, regh, ix, iy, iw, ih;
1130    int xx, yy;
1131
1132    if (!wd) return;
1133    wd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
1134    wd->zoom = wd->gest_start / gest->zoom;
1135    wd->size.ow = wd->size.w;
1136    wd->size.oh = wd->size.h;
1137    elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
1138    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
1139    if ((rw <= 0) || (rh <= 0)) return;
1140
1141    wd->size.nw = (double)wd->size.imw / wd->zoom;
1142    wd->size.nh = (double)wd->size.imh / wd->zoom;
1143
1144    elm_photocam_image_region_get(wd->obj, &regx, &regy, &regw, &regh);
1145    evas_object_geometry_get(wd->img, &ix, &iy, &iw, &ih);
1146
1147    wd->pvx = gest->x;
1148    wd->pvy = gest->y;
1149
1150    xx = (px / wd->zoom) - wd->pvx;
1151    yy = (py / wd->zoom) - wd->pvy;
1152    wd->gzoom.imx = 0;
1153    wd->gzoom.imy = 0;
1154
1155    if ((xx < 0) || (rw > wd->size.nw))
1156      {
1157         wd->gzoom.imx = xx;
1158         xx = 0;
1159      }
1160    else if ((xx + rw) > wd->size.nw)
1161      {
1162         wd->gzoom.imx = xx + rw - wd->size.nw;
1163         xx = wd->size.nw - rw;
1164      }
1165
1166    if ((yy < 0) || (rh > wd->size.nh))
1167      {
1168         wd->gzoom.imy = yy;
1169         yy = 0;
1170      }
1171    else if ((yy + rh) > wd->size.nh)
1172      {
1173         wd->gzoom.imy = yy + rh - wd->size.nh;
1174         yy = wd->size.nh - rh;
1175      }
1176
1177    wd->size.spos.x = (double)(xx + (rw / 2)) / (double)(wd->size.nw);
1178    wd->size.spos.y = (double)(yy + (rh / 2)) / (double)(wd->size.nh);
1179
1180    zoom_do(wd->obj, 1.0);
1181 }
1182
1183 static Evas_Event_Flags
1184 _gzoom_start(void *_wd, void *event_info)
1185 {
1186    Widget_Data *wd = (Widget_Data *)_wd;
1187    Elm_Gesture_Zoom_Info *p = (Elm_Gesture_Zoom_Info *) event_info;
1188    Evas_Coord rw, rh;
1189    int x,y,w,h;
1190    double marginx = 0, marginy = 0;
1191
1192    if (wd->gzoom.bounce.animator)
1193      {
1194         ecore_animator_del(wd->gzoom.bounce.animator);
1195         wd->gzoom.bounce.animator = NULL;
1196      }
1197    wd->zoom_gest = EINA_TRUE;
1198    _freeze_on(NULL, wd->obj, NULL);
1199
1200    elm_photocam_image_region_get(wd->obj, &x, &y, &w, &h);
1201    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
1202
1203    if (rw > wd->size.nw)
1204      marginx = (rw - wd->size.nw) / 2;
1205    if (rh > wd->size.nh)
1206      marginy = (rh - wd->size.nh) / 2;
1207
1208    wd->gest_start = wd->zoom;
1209
1210    wd->zoom_point_x = x + ((p->x - marginx) * wd->zoom) + wd->gzoom.imx;
1211    wd->zoom_point_y = y + ((p->y - marginy) * wd->zoom) + wd->gzoom.imy;
1212
1213    return EVAS_EVENT_FLAG_NONE;
1214 }
1215
1216 static Evas_Event_Flags
1217 _gzoom_move(void *_wd, void *event_info)
1218 {
1219    Widget_Data *wd = (Widget_Data *)_wd;
1220    Elm_Gesture_Zoom_Info *p = (Elm_Gesture_Zoom_Info *) event_info;
1221
1222    _gzoom(wd, wd->zoom_point_x, wd->zoom_point_y, p);
1223    return EVAS_EVENT_FLAG_NONE;
1224 }
1225
1226 static Evas_Event_Flags
1227 _gzoom_end(void *_wd, void *event_info __UNUSED__)
1228 {
1229    Widget_Data *wd = (Widget_Data *)_wd;
1230    Evas_Coord rw, rh;
1231
1232    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
1233    wd->gest_start = 1.0;
1234
1235    if (wd->gzoom.imx || wd->gzoom.imy)
1236      {
1237         double t;
1238
1239         t = ecore_loop_time_get();
1240         wd->gzoom.bounce.x_start = wd->gzoom.imx;
1241         wd->gzoom.bounce.y_start = wd->gzoom.imy;
1242         wd->gzoom.bounce.x_end = 0;
1243         wd->gzoom.bounce.y_end = 0;
1244
1245         if (rw > wd->size.nw &&
1246             rh > wd->size.nh)
1247           {
1248              Evas_Coord pw, ph;
1249              double z;
1250
1251              if ((wd->size.imw < rw) && (wd->size.imh < rh))
1252                {
1253                   wd->zoom = 1;
1254                   wd->size.nw = wd->size.imw;
1255                   wd->size.nh = wd->size.imh;
1256                }
1257              else
1258                {
1259                   ph = (wd->size.imh * rw) / wd->size.imw;
1260                   if (ph > rh)
1261                     {
1262                        pw = (wd->size.imw * rh) / wd->size.imh;
1263                        ph = rh;
1264                     }
1265                   else
1266                     {
1267                        pw = rw;
1268                     }
1269                   if (wd->size.imw > wd->size.imh)
1270                     z = (double)wd->size.imw / pw;
1271                   else
1272                     z = (double)wd->size.imh / ph;
1273
1274                   wd->zoom = z;
1275                   wd->size.nw = pw;
1276                   wd->size.nh = ph;
1277                }
1278              wd->gzoom.bounce.x_end = (wd->size.nw - rw) / 2;
1279              wd->gzoom.bounce.y_end = (wd->size.nh - rh) / 2;
1280           }
1281         else
1282           {
1283              int xx, yy;
1284
1285              xx = (wd->zoom_point_x / wd->zoom) - wd->pvx;
1286              yy = (wd->zoom_point_y / wd->zoom) - wd->pvy;
1287
1288              if (xx < 0) xx = 0;
1289              if (yy < 0) yy = 0;
1290
1291              if (rw > wd->size.nw)
1292                wd->gzoom.bounce.x_end = (wd->size.nw -rw) / 2;
1293              if ((xx + rw) > wd->size.nw)
1294                xx = wd->size.nw - rw;
1295
1296              if (rh > wd->size.nh)
1297                wd->gzoom.bounce.y_end = (wd->size.nh - rh) / 2;
1298              if ((yy + rh) > wd->size.nh)
1299                yy = wd->size.nh - rh;
1300
1301              wd->size.spos.x = (double)(xx + (rw / 2)) / (double)(wd->size.nw);
1302              wd->size.spos.y = (double)(yy + (rh / 2)) / (double)(wd->size.nh);
1303           }
1304
1305         wd->gzoom.bounce.t_start = t;
1306         wd->gzoom.bounce.t_end = t + _elm_config->page_scroll_friction;
1307
1308         wd->gzoom.bounce.animator = ecore_animator_add(_bounce_eval, wd);
1309      }
1310    else
1311      {
1312         _freeze_off(NULL, wd->obj, NULL);
1313         wd->zoom_gest = EINA_FALSE;
1314      }
1315
1316    return EVAS_EVENT_FLAG_NONE;
1317 }
1318
1319 EAPI Evas_Object *
1320 elm_photocam_add(Evas_Object *parent)
1321 {
1322    Evas_Object *obj;
1323    Evas *e;
1324    Widget_Data *wd;
1325    Evas_Coord minw, minh;
1326    static Evas_Smart *smart = NULL;
1327    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1328
1329    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1330
1331    ELM_SET_WIDTYPE(widtype, "photocam");
1332    elm_widget_type_set(obj, "photocam");
1333    elm_widget_sub_object_add(parent, obj);
1334    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1335    elm_widget_data_set(obj, wd);
1336    elm_widget_del_hook_set(obj, _del_hook);
1337    elm_widget_theme_hook_set(obj, _theme_hook);
1338    elm_widget_can_focus_set(obj, EINA_TRUE);
1339    elm_widget_event_hook_set(obj, _event_hook);
1340
1341    wd->scr = elm_smart_scroller_add(e);
1342    elm_smart_scroller_widget_set(wd->scr, obj);
1343    elm_smart_scroller_object_theme_set(obj, wd->scr, "photocam", "base", "default");
1344    evas_object_smart_callback_add(wd->scr, "scroll", _scr, obj);
1345    evas_object_smart_callback_add(wd->scr, "drag", _scr, obj);
1346    elm_widget_resize_object_set(obj, wd->scr);
1347
1348    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
1349    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
1350    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
1351    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
1352    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
1353
1354    elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
1355
1356    wd->obj = obj;
1357
1358    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1359    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1360    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1361    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1362
1363    if (!smart)
1364      {
1365         static Evas_Smart_Class sc;
1366
1367         evas_object_smart_clipped_smart_set(&_pan_sc);
1368         sc = _pan_sc;
1369         sc.name = "elm_photocam_pan";
1370         sc.version = EVAS_SMART_CLASS_VERSION;
1371         sc.add = _pan_add;
1372         sc.del = _pan_del;
1373         sc.resize = _pan_resize;
1374         sc.move = _pan_move;
1375         sc.calculate = _pan_calculate;
1376         smart = evas_smart_class_new(&sc);
1377      }
1378    if (smart)
1379      {
1380         wd->pan_smart = evas_object_smart_add(e, smart);
1381         wd->pan = evas_object_smart_data_get(wd->pan_smart);
1382         wd->pan->wd = wd;
1383      }
1384
1385    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
1386                                      _pan_set, _pan_get, _pan_max_get,
1387                                      _pan_min_get, _pan_child_size_get);
1388
1389    wd->zoom_gest = EINA_FALSE;
1390    wd->gest_start = 1.0;
1391    wd->zoom = 1;
1392    wd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
1393    wd->tsize = 512;
1394
1395    wd->img = evas_object_image_add(e);
1396    evas_object_image_load_orientation_set(wd->img, EINA_TRUE);
1397    evas_object_image_scale_hint_set(wd->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
1398    evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_DOWN,
1399                                   _mouse_down, obj);
1400    evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_UP,
1401                                   _mouse_up, obj);
1402    evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_MOVE,
1403                                   _mouse_move, obj);
1404    evas_object_image_scale_hint_set(wd->img, EVAS_IMAGE_SCALE_HINT_STATIC);
1405    evas_object_smart_member_add(wd->img, wd->pan_smart);
1406    elm_widget_sub_object_add(obj, wd->img);
1407    evas_object_image_filled_set(wd->img, 1);
1408    evas_object_event_callback_add(wd->img, EVAS_CALLBACK_IMAGE_PRELOADED,
1409                                   _main_preloaded, obj);
1410
1411    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
1412                              &minw, &minh);
1413    evas_object_size_hint_min_set(obj, minw, minh);
1414
1415    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1416
1417    _sizing_eval(obj);
1418    return obj;
1419 }
1420
1421 EAPI Evas_Load_Error
1422 elm_photocam_file_set(Evas_Object *obj, const char *file)
1423 {
1424    ELM_CHECK_WIDTYPE(obj, widtype) EVAS_LOAD_ERROR_NONE;
1425    Widget_Data *wd = elm_widget_data_get(obj);
1426    int w, h;
1427    if (!wd) return EVAS_LOAD_ERROR_GENERIC;
1428    if (!eina_stringshare_replace(&wd->file, file)) return EVAS_LOAD_ERROR_NONE;
1429    grid_clearall(obj);
1430
1431    evas_object_hide(wd->img);
1432    evas_object_image_smooth_scale_set(wd->img, (wd->nosmooth == 0));
1433    evas_object_image_file_set(wd->img, NULL, NULL);
1434    evas_object_image_load_scale_down_set(wd->img, 0);
1435    evas_object_image_file_set(wd->img, wd->file, NULL);
1436    evas_object_image_size_get(wd->img, &w, &h);
1437    wd->do_region = evas_object_image_region_support_get(wd->img);
1438    wd->size.imw = w;
1439    wd->size.imh = h;
1440    wd->size.w = wd->size.imw / wd->zoom;
1441    wd->size.h = wd->size.imh / wd->zoom;
1442    if (wd->gzoom.bounce.animator)
1443      {
1444         ecore_animator_del(wd->gzoom.bounce.animator);
1445         wd->gzoom.bounce.animator = NULL;
1446      }
1447    if (wd->zoom_animator)
1448      {
1449         wd->nosmooth--;
1450         if (wd->nosmooth == 0) _smooth_update(obj);
1451         ecore_animator_del(wd->zoom_animator);
1452         wd->zoom_animator = NULL;
1453      }
1454    evas_object_image_file_set(wd->img, NULL, NULL);
1455    evas_object_image_load_scale_down_set(wd->img, 8);
1456    evas_object_image_file_set(wd->img, wd->file, NULL);
1457    evas_object_image_preload(wd->img, 0);
1458    wd->main_load_pending = 1;
1459    if (wd->calc_job) ecore_job_del(wd->calc_job);
1460    wd->calc_job = ecore_job_add(_calc_job, wd);
1461    evas_object_smart_callback_call(obj, SIG_LOAD, NULL);
1462    wd->preload_num++;
1463    if (wd->preload_num == 1)
1464      {
1465         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1466                                 "elm,state,busy,start", "elm");
1467         evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
1468      }
1469    {
1470       double tz = wd->zoom;
1471       wd->zoom = 0.0;
1472       elm_photocam_zoom_set(wd->obj, tz);
1473    }
1474    return evas_object_image_load_error_get(wd->img);
1475 }
1476
1477 EAPI const char *
1478 elm_photocam_file_get(const Evas_Object *obj)
1479 {
1480    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1481    Widget_Data *wd = elm_widget_data_get(obj);
1482    if (!wd) return NULL;
1483    return wd->file;
1484 }
1485
1486 EAPI void
1487 elm_photocam_zoom_set(Evas_Object *obj, double zoom)
1488 {
1489    ELM_CHECK_WIDTYPE(obj, widtype);
1490    Widget_Data *wd = elm_widget_data_get(obj);
1491    Eina_List *l;
1492    Grid *g, *g_zoom = NULL;
1493    Evas_Coord pw, ph, rx, ry, rw, rh;
1494    double z;
1495    int zoom_changed = 0, started = 0;
1496    Ecore_Animator *an;
1497    if (!wd) return;
1498    if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0);
1499    if (zoom == wd->zoom) return;
1500    wd->zoom = zoom;
1501    wd->size.ow = wd->size.w;
1502    wd->size.oh = wd->size.h;
1503    elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
1504    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
1505    if ((rw <= 0) || (rh <= 0)) return;
1506
1507    if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
1508      {
1509         wd->size.nw = (double)wd->size.imw / wd->zoom;
1510         wd->size.nh = (double)wd->size.imh / wd->zoom;
1511      }
1512    else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT)
1513      {
1514         if ((wd->size.imw < 1) || (wd->size.imh < 1))
1515           {
1516              wd->size.nw = 0;
1517              wd->size.nh = 0;
1518           }
1519         else
1520           {
1521              ph = (wd->size.imh * rw) / wd->size.imw;
1522              if (ph > rh)
1523                {
1524                   pw = (wd->size.imw * rh) / wd->size.imh;
1525                   ph = rh;
1526                }
1527              else
1528                {
1529                   pw = rw;
1530                }
1531              if (wd->size.imw > wd->size.imh)
1532                z = (double)wd->size.imw / pw;
1533              else
1534                z = (double)wd->size.imh / ph;
1535              if (z != wd->zoom)
1536                zoom_changed = 1;
1537              wd->zoom = z;
1538              wd->size.nw = pw;
1539              wd->size.nh = ph;
1540           }
1541      }
1542    else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FILL)
1543      {
1544         if ((wd->size.imw < 1) || (wd->size.imh < 1))
1545           {
1546              wd->size.nw = 0;
1547              wd->size.nw = 0;
1548           }
1549         else
1550           {
1551              ph = (wd->size.imh * rw) / wd->size.imw;
1552              if (ph < rh)
1553                {
1554                   pw = (wd->size.imw * rh) / wd->size.imh;
1555                   ph = rh;
1556                }
1557              else
1558                {
1559                   pw = rw;
1560                }
1561              if (wd->size.imw > wd->size.imh)
1562                z = (double)wd->size.imw / pw;
1563              else
1564                z = (double)wd->size.imh / ph;
1565              if (z != wd->zoom)
1566                zoom_changed = 1;
1567              wd->zoom = z;
1568              wd->size.nw = pw;
1569              wd->size.nh = ph;
1570           }
1571      }
1572    else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT_IN)
1573      {
1574         if ((wd->size.imw < 1) || (wd->size.imh < 1))
1575           {
1576              wd->size.nw = 0;
1577              wd->size.nh = 0;
1578           }
1579         else if ((wd->size.imw < rw) && (wd->size.imh < rh))
1580           {
1581              if (1 != wd->zoom) zoom_changed = 1;
1582              wd->zoom = 1;
1583              wd->size.nw = wd->size.imw;
1584              wd->size.nh = wd->size.imh;
1585           }
1586         else
1587           {
1588              ph = (wd->size.imh * rw) / wd->size.imw;
1589              if (ph > rh)
1590                {
1591                   pw = (wd->size.imw * rh) / wd->size.imh;
1592                   ph = rh;
1593                }
1594              else
1595                pw = rw;
1596              if (wd->size.imw > wd->size.imh)
1597                z = (double)wd->size.imw / pw;
1598              else
1599                z = (double)wd->size.imh / ph;
1600              if (z != wd->zoom)
1601                zoom_changed = 1;
1602              wd->zoom = z;
1603              wd->size.nw = pw;
1604              wd->size.nh = ph;
1605           }
1606      }
1607    if (wd->main_load_pending)
1608      {
1609         wd->size.w = wd->size.nw;
1610         wd->size.h = wd->size.nh;
1611         goto done;
1612      }
1613    EINA_LIST_FOREACH(wd->grids, l, g)
1614      {
1615         if (g->zoom == grid_zoom_calc(wd->zoom))
1616           {
1617              wd->grids = eina_list_remove(wd->grids, g);
1618              wd->grids = eina_list_prepend(wd->grids, g);
1619              _grid_raise(g);
1620              goto done;
1621           }
1622      }
1623    g = grid_create(obj);
1624    if (g)
1625      {
1626         if (eina_list_count(wd->grids) > 1)
1627           {
1628              g_zoom = eina_list_last(wd->grids)->data;
1629              wd->grids = eina_list_remove(wd->grids, g_zoom);
1630              grid_clear(obj, g_zoom);
1631              free(g_zoom);
1632              EINA_LIST_FOREACH(wd->grids, l, g_zoom)
1633                {
1634                   g_zoom->dead = 1;
1635                }
1636           }
1637         wd->grids = eina_list_prepend(wd->grids, g);
1638      }
1639    else
1640      {
1641         EINA_LIST_FREE(wd->grids, g)
1642           {
1643              grid_clear(obj, g);
1644              free(g);
1645           }
1646      }
1647  done:
1648    wd->t_start = ecore_loop_time_get();
1649    wd->t_end = wd->t_start + _elm_config->zoom_friction;
1650    if ((wd->size.w > 0) && (wd->size.h > 0))
1651      {
1652         wd->size.spos.x = (double)(rx + (rw / 2)) / (double)wd->size.w;
1653         wd->size.spos.y = (double)(ry + (rh / 2)) / (double)wd->size.h;
1654      }
1655    else
1656      {
1657         wd->size.spos.x = 0.5;
1658         wd->size.spos.y = 0.5;
1659      }
1660    if (rw > wd->size.w) wd->size.spos.x = 0.5;
1661    if (rh > wd->size.h) wd->size.spos.y = 0.5;
1662    if (wd->size.spos.x > 1.0) wd->size.spos.x = 1.0;
1663    if (wd->size.spos.y > 1.0) wd->size.spos.y = 1.0;
1664    if (wd->paused)
1665      {
1666         zoom_do(obj, 1.0);
1667      }
1668    else
1669      {
1670         if (!wd->zoom_animator)
1671           {
1672              wd->zoom_animator = ecore_animator_add(_zoom_anim, obj);
1673              wd->nosmooth++;
1674              if (wd->nosmooth == 1) _smooth_update(obj);
1675              started = 1;
1676           }
1677      }
1678    an = wd->zoom_animator;
1679    if (an)
1680      {
1681         if (!_zoom_anim(obj))
1682           {
1683              ecore_animator_del(an);
1684              an = NULL;
1685           }
1686      }
1687    if (wd->calc_job) ecore_job_del(wd->calc_job);
1688    wd->calc_job = ecore_job_add(_calc_job, wd);
1689    if (!wd->paused)
1690      {
1691         if (started)
1692           evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL);
1693         if (!an)
1694           evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1695      }
1696    if (zoom_changed)
1697      evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL);
1698 }
1699
1700 EAPI double
1701 elm_photocam_zoom_get(const Evas_Object *obj)
1702 {
1703    ELM_CHECK_WIDTYPE(obj, widtype) 1.0;
1704    Widget_Data *wd = elm_widget_data_get(obj);
1705    if (!wd) return 1.0;
1706    return wd->zoom;
1707 }
1708
1709 EAPI void
1710 elm_photocam_zoom_mode_set(Evas_Object *obj, Elm_Photocam_Zoom_Mode mode)
1711 {
1712    ELM_CHECK_WIDTYPE(obj, widtype);
1713    Widget_Data *wd = elm_widget_data_get(obj);
1714    if (!wd) return;
1715    if (wd->mode == mode) return;
1716    wd->mode = mode;
1717    {
1718       double tz = wd->zoom;
1719       wd->zoom = 0.0;
1720       elm_photocam_zoom_set(wd->obj, tz);
1721    }
1722 }
1723
1724 EAPI Elm_Photocam_Zoom_Mode
1725 elm_photocam_zoom_mode_get(const Evas_Object *obj)
1726 {
1727    ELM_CHECK_WIDTYPE(obj, widtype) ELM_PHOTOCAM_ZOOM_MODE_LAST;
1728    Widget_Data *wd = elm_widget_data_get(obj);
1729    if (!wd) return ELM_PHOTOCAM_ZOOM_MODE_LAST;
1730    return wd->mode;
1731 }
1732
1733 EAPI void
1734 elm_photocam_image_size_get(const Evas_Object *obj, int *w, int *h)
1735 {
1736    ELM_CHECK_WIDTYPE(obj, widtype);
1737    Widget_Data *wd = elm_widget_data_get(obj);
1738    if (!wd) return;
1739    if (w) *w = wd->size.imw;
1740    if (h) *h = wd->size.imh;
1741 }
1742
1743 EAPI void
1744 elm_photocam_image_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h)
1745 {
1746    ELM_CHECK_WIDTYPE(obj, widtype);
1747    Widget_Data *wd = elm_widget_data_get(obj);
1748    Evas_Coord sx, sy, sw, sh;
1749    if (!wd) return;
1750    elm_smart_scroller_child_pos_get(wd->scr, &sx, &sy);
1751    elm_smart_scroller_child_viewport_size_get(wd->scr, &sw, &sh);
1752    if (wd->size.w > 0)
1753      {
1754         if (x)
1755           {
1756              *x = (wd->size.imw * sx) / wd->size.w;
1757              if (*x > wd->size.imw) *x = wd->size.imw;
1758           }
1759         if (w)
1760           {
1761              *w = (wd->size.imw * sw) / wd->size.w;
1762              if (*w > wd->size.imw) *w = wd->size.imw;
1763              else if (*w < 0) *w = 0;
1764           }
1765      }
1766    else
1767      {
1768         if (x) *x = 0;
1769         if (w) *w = 0;
1770      }
1771
1772    if (wd->size.h > 0)
1773      {
1774         if (y)
1775           {
1776              *y = (wd->size.imh * sy) / wd->size.h;
1777              if (*y > wd->size.imh) *y = wd->size.imh;
1778           }
1779         if (h)
1780           {
1781              *h = (wd->size.imh * sh) / wd->size.h;
1782              if (*h > wd->size.imh) *h = wd->size.imh;
1783              else if (*h < 0) *h = 0;
1784           }
1785      }
1786    else
1787      {
1788         if (y) *y = 0;
1789         if (h) *h = 0;
1790      }
1791 }
1792
1793 EAPI void
1794 elm_photocam_image_region_show(Evas_Object *obj, int x, int y, int w, int h __UNUSED__)
1795 {
1796    ELM_CHECK_WIDTYPE(obj, widtype);
1797    Widget_Data *wd = elm_widget_data_get(obj);
1798    int rx, ry, rw, rh;
1799    if (!wd) return;
1800    if ((wd->size.imw < 1) || (wd->size.imh < 1)) return;
1801    rx = (x * wd->size.w) / wd->size.imw;
1802    ry = (y * wd->size.h) / wd->size.imh;
1803    rw = (w * wd->size.w) / wd->size.imw;
1804    rh = (h * wd->size.h) / wd->size.imh;
1805    if (rw < 1) rw = 1;
1806    if (rh < 1) rh = 1;
1807    if ((rx + rw) > wd->size.w) rx = wd->size.w - rw;
1808    if ((ry + rh) > wd->size.h) ry = wd->size.h - rh;
1809    if (wd->gzoom.bounce.animator)
1810      {
1811         ecore_animator_del(wd->gzoom.bounce.animator);
1812         wd->gzoom.bounce.animator = NULL;
1813         zoom_do(obj, 1.0);
1814      }
1815    if (wd->zoom_animator)
1816      {
1817         wd->nosmooth--;
1818         ecore_animator_del(wd->zoom_animator);
1819         wd->zoom_animator = NULL;
1820         zoom_do(obj, 1.0);
1821         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1822      }
1823    elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh);
1824 }
1825
1826 EAPI void
1827 elm_photocam_image_region_bring_in(Evas_Object *obj, int x, int y, int w, int h __UNUSED__)
1828 {
1829    ELM_CHECK_WIDTYPE(obj, widtype);
1830    Widget_Data *wd = elm_widget_data_get(obj);
1831    int rx, ry, rw, rh;
1832    if (!wd) return;
1833    if ((wd->size.imw < 1) || (wd->size.imh < 1)) return;
1834    rx = (x * wd->size.w) / wd->size.imw;
1835    ry = (y * wd->size.h) / wd->size.imh;
1836    rw = (w * wd->size.w) / wd->size.imw;
1837    rh = (h * wd->size.h) / wd->size.imh;
1838    if (rw < 1) rw = 1;
1839    if (rh < 1) rh = 1;
1840    if ((rx + rw) > wd->size.w) rx = wd->size.w - rw;
1841    if ((ry + rh) > wd->size.h) ry = wd->size.h - rh;
1842    if (wd->gzoom.bounce.animator)
1843      {
1844         ecore_animator_del(wd->gzoom.bounce.animator);
1845         wd->gzoom.bounce.animator = NULL;
1846         zoom_do(obj, 1.0);
1847      }
1848    if (wd->zoom_animator)
1849      {
1850         wd->nosmooth--;
1851         if (!wd->nosmooth) _smooth_update(obj);
1852         ecore_animator_del(wd->zoom_animator);
1853         wd->zoom_animator = NULL;
1854         zoom_do(obj, 1.0);
1855         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1856      }
1857    elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh);
1858 }
1859
1860 EAPI void
1861 elm_photocam_paused_set(Evas_Object *obj, Eina_Bool paused)
1862 {
1863    ELM_CHECK_WIDTYPE(obj, widtype);
1864    Widget_Data *wd = elm_widget_data_get(obj);
1865    if (!wd) return;
1866    if (wd->paused == !!paused) return;
1867    wd->paused = paused;
1868    if (wd->paused)
1869      {
1870         if (wd->gzoom.bounce.animator)
1871           {
1872              ecore_animator_del(wd->gzoom.bounce.animator);
1873              wd->gzoom.bounce.animator = NULL;
1874              zoom_do(obj, 1.0);
1875           }
1876         if (wd->zoom_animator)
1877           {
1878              ecore_animator_del(wd->zoom_animator);
1879              wd->zoom_animator = NULL;
1880              zoom_do(obj, 1.0);
1881              evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1882           }
1883      }
1884 }
1885
1886 EAPI Eina_Bool
1887 elm_photocam_paused_get(const Evas_Object *obj)
1888 {
1889    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1890    Widget_Data *wd = elm_widget_data_get(obj);
1891    if (!wd) return EINA_FALSE;
1892    return wd->paused;
1893 }
1894
1895 EAPI Evas_Object *
1896 elm_photocam_internal_image_get(const Evas_Object *obj)
1897 {
1898    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1899    Widget_Data *wd = elm_widget_data_get(obj);
1900    if (!wd) return NULL;
1901    return wd->img;
1902 }
1903
1904 EAPI void
1905 elm_photocam_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1906 {
1907    ELM_CHECK_WIDTYPE(obj, widtype);
1908    Widget_Data *wd = elm_widget_data_get(obj);
1909    if (!wd) return;
1910    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
1911 }
1912
1913 EAPI void
1914 elm_photocam_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
1915 {
1916    ELM_CHECK_WIDTYPE(obj, widtype);
1917    Widget_Data *wd = elm_widget_data_get(obj);
1918    if (!wd) return;
1919    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
1920 }
1921
1922 EAPI void
1923 elm_photocam_gesture_enabled_set(Evas_Object *obj, Eina_Bool gesture)
1924 {
1925    ELM_CHECK_WIDTYPE(obj, widtype);
1926    Widget_Data *wd = elm_widget_data_get(obj);
1927    if (!wd) return;
1928    if (wd->do_gesture == !!gesture) return;
1929
1930    if (wd->gest)
1931      {
1932         evas_object_del(wd->gest);
1933         wd->gest = NULL;
1934      }
1935
1936    if (gesture)
1937      {
1938         wd->gest = elm_gesture_layer_add(wd->obj);
1939         if (!wd->gest) return;
1940         elm_gesture_layer_attach(wd->gest, wd->obj);
1941         elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_START,
1942                                  _gzoom_start, wd);
1943         elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_MOVE,
1944                                  _gzoom_move, wd);
1945         elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_END,
1946                                  _gzoom_end, wd);
1947         elm_gesture_layer_cb_set(wd->gest, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_ABORT,
1948                                  _gzoom_end, wd);
1949      }
1950
1951    wd->do_gesture = !!gesture;
1952 }
1953
1954 EAPI Eina_Bool
1955 elm_photocam_gesture_enabled_get(const Evas_Object *obj)
1956 {
1957    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1958    Widget_Data *wd = elm_widget_data_get(obj);
1959    if (!wd) return EINA_FALSE;
1960
1961    return wd->do_gesture;
1962 }