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