1 #include <Elementary.h>
3 #include "els_scroller.h"
6 * TODO (maybe - optional future stuff):
8 * 1. wrap photo in theme edje so u can have styling around photo (like white
11 * 3. rotation flags in exif handling (nasty! should have rot in evas)
14 typedef struct _Widget_Data Widget_Data;
15 typedef struct _Pan Pan;
16 typedef struct _Grid Grid;
17 typedef struct _Grid_Item Grid_Item;
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
46 Evas_Object *pan_smart;
48 Evas_Coord pan_x, pan_y, minw, minh;
51 Elm_Photocam_Zoom_Mode mode;
55 Ecore_Timer *scr_timer;
56 Ecore_Timer *long_timer;
57 Ecore_Animator *zoom_animator;
58 double t_start, t_end;
72 Evas_Coord x, y ,w ,h;
75 Evas_Object *img; // low res version of image (scale down == 8)
79 Eina_Bool main_load_pending : 1;
80 Eina_Bool resized : 1;
81 Eina_Bool longpressed : 1;
82 Eina_Bool on_hold : 1;
84 Eina_Bool do_region : 1;
89 Evas_Object_Smart_Clipped_Data __clipped_data;
93 static const char *widtype = NULL;
94 static void _del_hook(Evas_Object *obj);
95 static void _theme_hook(Evas_Object *obj);
96 static void _on_focus_hook(void *data, Evas_Object *obj);
97 //static void _show_region_hook(void *data, Evas_Object *obj);
98 static void _sizing_eval(Evas_Object *obj);
99 static void _calc_job(void *data);
100 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__,
101 Evas_Callback_Type type, void *event_info);
102 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);
103 static void grid_clear(Evas_Object *obj, Grid *g);
104 static Grid *grid_create(Evas_Object *obj);
105 static void grid_load(Evas_Object *obj, Grid *g);
107 static const char SIG_CLICKED[] = "clicked";
108 static const char SIG_PRESS[] = "press";
109 static const char SIG_LONGPRESSED[] = "longpressed";
110 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
111 static const char SIG_LOAD[] = "load";
112 static const char SIG_LOADED[] = "loaded";
113 static const char SIG_LOAD_DETAIL[] = "load,detail";
114 static const char SIG_LOADED_DETAIL[] = "loaded,detail";
115 static const char SIG_ZOOM_START[] = "zoom,start";
116 static const char SIG_ZOOM_STOP[] = "zoom,stop";
117 static const char SIG_ZOOM_CHANGE[] = "zoom,change";
118 static const char SIG_SCROLL[] = "scroll";
119 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
120 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
121 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
122 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
124 static const Evas_Smart_Cb_Description _signals[] = {
127 {SIG_LONGPRESSED, ""},
128 {SIG_CLICKED_DOUBLE, ""},
131 {SIG_LOAD_DETAIL, ""},
132 {SIG_LOADED_DETAIL, ""},
133 {SIG_ZOOM_START, ""},
135 {SIG_ZOOM_CHANGE, ""},
137 {SIG_SCROLL_ANIM_START, ""},
138 {SIG_SCROLL_ANIM_STOP, ""},
139 {SIG_SCROLL_DRAG_START, ""},
140 {SIG_SCROLL_DRAG_STOP, ""},
146 nearest_pow2(int num)
148 unsigned int n = num - 1;
158 img_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
160 Widget_Data *wd = elm_widget_data_get(obj);
161 Evas_Coord ax, ay, gw, gh;
167 if (ow > gw) ax = (ow - gw) / 2;
168 if (oh > gh) ay = (oh - gh) / 2;
169 evas_object_move(wd->img, ox + 0 - px + ax, oy + 0 - py + ay);
170 evas_object_resize(wd->img, gw, gh);
174 wd->show.show = EINA_FALSE;
175 elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h);
180 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)
182 Widget_Data *wd = elm_widget_data_get(obj);
183 Evas_Coord ax, ay, gw, gh, tx, ty;
190 if (ow > gw) ax = (ow - gw) / 2;
191 if (oh > gh) ay = (oh - gh) / 2;
192 for (y = 0; y < g->gh; y++)
194 for (x = 0; x < g->gw; x++)
196 int tn, xx, yy, ww, hh;
198 tn = (y * g->gw) + x;
199 xx = g->grid[tn].out.x;
200 yy = g->grid[tn].out.y;
201 ww = g->grid[tn].out.w;
202 hh = g->grid[tn].out.h;
203 if ((gw != g->w) && (g->w > 0))
206 xx = (gw * xx) / g->w;
207 ww = ((gw * (tx + ww)) / g->w) - xx;
209 if ((gh != g->h) && (g->h > 0))
212 yy = (gh * yy) / g->h;
213 hh = ((gh * (ty + hh)) / g->h) - yy;
215 evas_object_move(g->grid[tn].img,
218 evas_object_resize(g->grid[tn].img, ww, hh);
224 grid_clear(Evas_Object *obj, Grid *g)
226 Widget_Data *wd = elm_widget_data_get(obj);
229 if (!g->grid) return;
230 for (y = 0; y < g->gh; y++)
232 for (x = 0; x < g->gw; x++)
236 tn = (y * g->gw) + x;
237 evas_object_del(g->grid[tn].img);
238 if (g->grid[tn].want)
241 if (!wd->preload_num)
243 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
244 "elm,state,busy,stop", "elm");
245 evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
257 _tile_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
259 Grid_Item *git = data;
264 evas_object_show(git->img);
266 git->wd->preload_num--;
267 if (!git->wd->preload_num)
269 edje_object_signal_emit(elm_smart_scroller_edje_object_get(git->wd->scr),
270 "elm,state,busy,stop", "elm");
271 evas_object_smart_callback_call(git->wd->obj, SIG_LOADED_DETAIL, NULL);
277 grid_zoom_calc(double zoom)
281 return nearest_pow2(z);
285 grid_create(Evas_Object *obj)
287 Widget_Data *wd = elm_widget_data_get(obj);
291 if (!wd) return NULL;
292 g = calloc(1, sizeof(Grid));
295 g->zoom = grid_zoom_calc(wd->zoom);
296 g->tsize = wd->tsize;
297 g->iw = wd->size.imw;
298 g->ih = wd->size.imh;
300 g->w = g->iw / g->zoom;
301 g->h = g->ih / g->zoom;
309 g->gw = (g->w + g->tsize - 1) / g->tsize;
310 g->gh = (g->h + g->tsize - 1) / g->tsize;
317 g->grid = calloc(1, sizeof(Grid_Item) * g->gw * g->gh);
324 for (y = 0; y < g->gh; y++)
326 for (x = 0; x < g->gw; x++)
330 tn = (y * g->gw) + x;
331 g->grid[tn].src.x = x * g->tsize;
332 if (x == (g->gw - 1))
333 g->grid[tn].src.w = g->w - ((g->gw - 1) * g->tsize);
335 g->grid[tn].src.w = g->tsize;
336 g->grid[tn].src.y = y * g->tsize;
337 if (y == (g->gh - 1))
338 g->grid[tn].src.h = g->h - ((g->gh - 1) * g->tsize);
340 g->grid[tn].src.h = g->tsize;
342 g->grid[tn].out.x = g->grid[tn].src.x;
343 g->grid[tn].out.y = g->grid[tn].src.y;
344 g->grid[tn].out.w = g->grid[tn].src.w;
345 g->grid[tn].out.h = g->grid[tn].src.h;
349 evas_object_image_add(evas_object_evas_get(obj));
350 evas_object_image_load_orientation_set(g->grid[tn].img, EINA_TRUE);
351 evas_object_image_scale_hint_set
352 (g->grid[tn].img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
353 evas_object_pass_events_set(g->grid[tn].img, EINA_TRUE);
354 evas_object_smart_member_add(g->grid[tn].img,
356 elm_widget_sub_object_add(obj, g->grid[tn].img);
357 evas_object_image_filled_set(g->grid[tn].img, 1);
358 evas_object_event_callback_add(g->grid[tn].img,
359 EVAS_CALLBACK_IMAGE_PRELOADED,
368 grid_load(Evas_Object *obj, Grid *g)
370 Widget_Data *wd = elm_widget_data_get(obj);
372 Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, gw, gh, tx, ty;
374 evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
375 evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
378 for (y = 0; y < g->gh; y++)
380 for (x = 0; x < g->gw; x++)
382 int tn, xx, yy, ww, hh;
383 Eina_Bool visible = EINA_FALSE;
385 tn = (y * g->gw) + x;
386 xx = g->grid[tn].out.x;
387 yy = g->grid[tn].out.y;
388 ww = g->grid[tn].out.w;
389 hh = g->grid[tn].out.h;
390 if ((gw != g->w) && (g->w > 0))
393 xx = (gw * xx) / g->w;
394 ww = ((gw * (tx + ww)) / g->w) - xx;
396 if ((gh != g->h) && (g->h > 0))
399 yy = (gh * yy) / g->h;
400 hh = ((gh * (ty + hh)) / g->h) - yy;
402 if (ELM_RECTS_INTERSECT(xx - wd->pan_x + ox,
407 if ((visible) && (!g->grid[tn].have) && (!g->grid[tn].want))
409 g->grid[tn].want = 1;
410 evas_object_hide(g->grid[tn].img);
411 evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
412 evas_object_image_load_scale_down_set(g->grid[tn].img, g->zoom);
413 evas_object_image_load_region_set(g->grid[tn].img,
418 evas_object_image_file_set(g->grid[tn].img, wd->file, NULL);
419 evas_object_image_preload(g->grid[tn].img, 0);
421 if (wd->preload_num == 1)
423 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
424 "elm,state,busy,start", "elm");
425 evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
428 else if ((g->grid[tn].want) && (!visible))
431 if (!wd->preload_num)
433 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
434 "elm,state,busy,stop", "elm");
435 evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
437 g->grid[tn].want = 0;
438 evas_object_hide(g->grid[tn].img);
439 evas_object_image_preload(g->grid[tn].img, 1);
440 evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
442 else if ((g->grid[tn].have) && (!visible))
444 g->grid[tn].have = 0;
445 evas_object_hide(g->grid[tn].img);
446 evas_object_image_preload(g->grid[tn].img, 1);
447 evas_object_image_file_set(g->grid[tn].img, NULL, NULL);
454 grid_clearall(Evas_Object *obj)
456 Widget_Data *wd = elm_widget_data_get(obj);
459 EINA_LIST_FREE(wd->grids, g)
467 _smooth_update(Evas_Object *obj)
469 Widget_Data *wd = elm_widget_data_get(obj);
474 EINA_LIST_FOREACH(wd->grids, l, g)
476 for (y = 0; y < g->gh; y++)
478 for (x = 0; x < g->gw; x++)
482 tn = (y * g->gw) + x;
483 evas_object_image_smooth_scale_set(g->grid[tn].img, (!wd->nosmooth));
487 evas_object_image_smooth_scale_set(wd->img, (!wd->nosmooth));
495 for (y = 0; y < g->gh; y++)
497 for (x = 0; x < g->gw; x++)
501 tn = (y * g->gw) + x;
502 evas_object_raise(g->grid[tn].img);
508 _scr_timeout(void *data)
510 Widget_Data *wd = elm_widget_data_get(data);
511 if (!wd) return ECORE_CALLBACK_CANCEL;
513 if (!wd->nosmooth) _smooth_update(data);
514 wd->scr_timer = NULL;
515 return ECORE_CALLBACK_CANCEL;
519 _scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
521 Widget_Data *wd = elm_widget_data_get(data);
526 if (wd->nosmooth == 1) _smooth_update(data);
528 if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
529 wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
533 _main_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
535 Evas_Object *obj = data;
536 Widget_Data *wd = elm_widget_data_get(obj);
539 evas_object_show(wd->img);
540 wd->main_load_pending = 0;
541 g = grid_create(obj);
544 wd->grids = eina_list_prepend(wd->grids, g);
545 grid_load(wd->obj, g);
547 if (wd->calc_job) ecore_job_del(wd->calc_job);
548 wd->calc_job = ecore_job_add(_calc_job, wd);
549 evas_object_smart_callback_call(data, SIG_LOADED, NULL);
551 if (!wd->preload_num)
553 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
554 "elm,state,busy,stop", "elm");
555 evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
560 zoom_do(Evas_Object *obj, double t)
562 Widget_Data *wd = elm_widget_data_get(obj);
563 Evas_Coord xx, yy, ow, oh;
564 if (!wd) return ECORE_CALLBACK_CANCEL;
565 wd->size.w = (wd->size.ow * (1.0 - t)) + (wd->size.nw * t);
566 wd->size.h = (wd->size.oh * (1.0 - t)) + (wd->size.nh * t);
567 elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
568 xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
569 yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
571 else if (xx > (wd->size.w - ow)) xx = wd->size.w - ow;
573 else if (yy > (wd->size.h - oh)) yy = wd->size.h - oh;
575 wd->show.show = EINA_TRUE;
581 if (wd->calc_job) ecore_job_del(wd->calc_job);
582 wd->calc_job = ecore_job_add(_calc_job, wd);
585 Eina_List *l, *l_next;
588 EINA_LIST_FOREACH_SAFE(wd->grids, l, l_next, g)
592 wd->grids = eina_list_remove_list(wd->grids, l);
597 return ECORE_CALLBACK_CANCEL;
599 return ECORE_CALLBACK_RENEW;
604 _zoom_anim(void *data)
606 Evas_Object *obj = data;
607 Widget_Data *wd = elm_widget_data_get(obj);
610 if (!wd) return ECORE_CALLBACK_CANCEL;
611 t = ecore_loop_time_get();
614 else if (wd->t_end > wd->t_start)
615 t = (t - wd->t_start) / (wd->t_end - wd->t_start);
620 go = zoom_do(obj, t);
624 if (!wd->nosmooth) _smooth_update(data);
625 wd->zoom_animator = NULL;
626 evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
632 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
634 Widget_Data *wd = elm_widget_data_get(data);
635 // Evas_Event_Mouse_Move *ev = event_info;
640 _long_press(void *data)
642 Widget_Data *wd = elm_widget_data_get(data);
643 if (!wd) return ECORE_CALLBACK_CANCEL;
644 wd->long_timer = NULL;
645 wd->longpressed = EINA_TRUE;
646 evas_object_smart_callback_call(data, SIG_LONGPRESSED, NULL);
647 return ECORE_CALLBACK_CANCEL;
651 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
653 Widget_Data *wd = elm_widget_data_get(data);
654 Evas_Event_Mouse_Down *ev = event_info;
656 if (ev->button != 1) return;
657 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
658 else wd->on_hold = EINA_FALSE;
659 if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
660 evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, NULL);
662 evas_object_smart_callback_call(data, SIG_PRESS, NULL);
663 wd->longpressed = EINA_FALSE;
664 if (wd->long_timer) ecore_timer_del(wd->long_timer);
665 wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data);
669 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
671 Widget_Data *wd = elm_widget_data_get(data);
672 Evas_Event_Mouse_Up *ev = event_info;
674 if (ev->button != 1) return;
675 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
676 else wd->on_hold = EINA_FALSE;
679 ecore_timer_del(wd->long_timer);
680 wd->long_timer = NULL;
683 evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
684 wd->on_hold = EINA_FALSE;
687 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL;
690 _del_hook(Evas_Object *obj)
692 Widget_Data *wd = elm_widget_data_get(obj);
695 EINA_LIST_FREE(wd->grids, g)
697 if (g->grid) free(g->grid);
700 evas_object_del(wd->pan_smart);
701 wd->pan_smart = NULL;
702 if (wd->file) eina_stringshare_del(wd->file);
703 if (wd->calc_job) ecore_job_del(wd->calc_job);
704 if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
705 if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
706 if (wd->long_timer) ecore_timer_del(wd->long_timer);
711 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
713 Widget_Data *wd = elm_widget_data_get(obj);
715 if (elm_widget_focus_get(obj))
717 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm");
718 evas_object_focus_set(wd->obj, EINA_TRUE);
722 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm");
723 evas_object_focus_set(wd->obj, EINA_FALSE);
728 _theme_hook(Evas_Object *obj)
730 Widget_Data *wd = elm_widget_data_get(obj);
732 elm_smart_scroller_object_theme_set(obj, wd->scr, "photocam", "base", elm_widget_style_get(obj));
733 // edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
739 _show_region_hook(void *data, Evas_Object *obj)
741 Widget_Data *wd = elm_widget_data_get(data);
742 Evas_Coord x, y, w, h;
744 elm_widget_show_region_get(obj, &x, &y, &w, &h);
745 elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
750 _sizing_eval(Evas_Object *obj)
752 Widget_Data *wd = elm_widget_data_get(obj);
753 Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
755 // evas_object_size_hint_min_get(wd->scr, &minw, &minh);
756 evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
759 // if (wd->mode != ELM_LIST_LIMIT) minw = -1;
760 evas_object_size_hint_min_set(obj, minw, minh);
761 evas_object_size_hint_max_set(obj, maxw, maxh);
765 _calc_job(void *data)
767 Widget_Data *wd = data;
768 Evas_Coord minw, minh;
775 if (wd->mode != ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
777 double tz = wd->zoom;
779 elm_photocam_zoom_set(wd->obj, tz);
782 if ((minw != wd->minw) || (minh != wd->minh))
786 evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
787 _sizing_eval(wd->obj);
790 evas_object_smart_changed(wd->pan_smart);
794 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
796 Pan *sd = evas_object_smart_data_get(obj);
798 if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
801 evas_object_smart_changed(obj);
805 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
807 Pan *sd = evas_object_smart_data_get(obj);
809 if (x) *x = sd->wd->pan_x;
810 if (y) *y = sd->wd->pan_y;
814 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
816 Pan *sd = evas_object_smart_data_get(obj);
819 evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
820 ow = sd->wd->minw - ow;
822 oh = sd->wd->minh - oh;
829 _pan_min_get(Evas_Object *obj __UNUSED__, Evas_Coord *x, Evas_Coord *y)
836 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
838 Pan *sd = evas_object_smart_data_get(obj);
840 if (w) *w = sd->wd->minw;
841 if (h) *h = sd->wd->minh;
845 _pan_add(Evas_Object *obj)
848 Evas_Object_Smart_Clipped_Data *cd;
850 cd = evas_object_smart_data_get(obj);
852 sd = calloc(1, sizeof(Pan));
854 sd->__clipped_data = *cd;
856 evas_object_smart_data_set(obj, sd);
860 _pan_del(Evas_Object *obj)
862 Pan *sd = evas_object_smart_data_get(obj);
868 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
870 Pan *sd = evas_object_smart_data_get(obj);
873 evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
874 if ((ow == w) && (oh == h)) return;
876 if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
877 sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
881 _pan_calculate(Evas_Object *obj)
883 Pan *sd = evas_object_smart_data_get(obj);
884 Evas_Coord ox, oy, ow, oh;
888 evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
889 img_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
890 EINA_LIST_FOREACH(sd->wd->grids, l, g)
892 grid_load(sd->wd->obj, g);
893 grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
898 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
900 Pan *sd = evas_object_smart_data_get(obj);
902 if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
903 sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
907 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
909 Widget_Data *wd = elm_widget_data_get(obj);
911 elm_smart_scroller_hold_set(wd->scr, 1);
915 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
917 Widget_Data *wd = elm_widget_data_get(obj);
919 elm_smart_scroller_hold_set(wd->scr, 0);
923 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
925 Widget_Data *wd = elm_widget_data_get(obj);
927 elm_smart_scroller_freeze_set(wd->scr, 1);
931 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
933 Widget_Data *wd = elm_widget_data_get(obj);
935 elm_smart_scroller_freeze_set(wd->scr, 0);
939 _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
941 evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
945 _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
947 evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
951 _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
953 evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
957 _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
959 evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
963 _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
965 evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
969 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__,
970 Evas_Callback_Type type, void *event_info)
973 if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
974 Evas_Event_Key_Down *ev = event_info;
975 Widget_Data *wd = elm_widget_data_get(obj);
976 if (!wd) return EINA_FALSE;
977 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
981 Evas_Coord step_x = 0;
982 Evas_Coord step_y = 0;
985 Evas_Coord page_x = 0;
986 Evas_Coord page_y = 0;
988 elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
989 elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
990 elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
991 elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
993 if ((!strcmp(ev->keyname, "Left")) ||
994 (!strcmp(ev->keyname, "KP_Left")))
998 else if ((!strcmp(ev->keyname, "Right")) ||
999 (!strcmp(ev->keyname, "KP_Right")))
1003 else if ((!strcmp(ev->keyname, "Up")) ||
1004 (!strcmp(ev->keyname, "KP_Up")))
1008 else if ((!strcmp(ev->keyname, "Down")) ||
1009 (!strcmp(ev->keyname, "KP_Down")))
1013 else if ((!strcmp(ev->keyname, "Prior")) ||
1014 (!strcmp(ev->keyname, "KP_Prior")))
1017 y -= -(page_y * v_h) / 100;
1021 else if ((!strcmp(ev->keyname, "Next")) ||
1022 (!strcmp(ev->keyname, "KP_Next")))
1025 y += -(page_y * v_h) / 100;
1029 else if ((!strcmp(ev->keyname, "KP_Add")))
1031 zoom = elm_photocam_zoom_get(obj);
1033 elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL);
1034 elm_photocam_zoom_set(obj, zoom);
1037 else if ((!strcmp(ev->keyname, "KP_Subtract")))
1039 zoom = elm_photocam_zoom_get(obj);
1041 elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_MANUAL);
1042 elm_photocam_zoom_set(obj, zoom);
1045 else return EINA_FALSE;
1047 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1048 elm_smart_scroller_child_pos_set(wd->scr, x, y);
1054 elm_photocam_add(Evas_Object *parent)
1059 Evas_Coord minw, minh;
1060 static Evas_Smart *smart = NULL;
1061 Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1063 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1065 ELM_SET_WIDTYPE(widtype, "photocam");
1066 elm_widget_type_set(obj, "photocam");
1067 elm_widget_sub_object_add(parent, obj);
1068 elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1069 elm_widget_data_set(obj, wd);
1070 elm_widget_del_hook_set(obj, _del_hook);
1071 elm_widget_theme_hook_set(obj, _theme_hook);
1072 elm_widget_can_focus_set(obj, EINA_TRUE);
1073 elm_widget_event_hook_set(obj, _event_hook);
1075 wd->scr = elm_smart_scroller_add(e);
1076 elm_smart_scroller_widget_set(wd->scr, obj);
1077 elm_smart_scroller_object_theme_set(obj, wd->scr, "photocam", "base", "default");
1078 evas_object_smart_callback_add(wd->scr, "scroll", _scr, obj);
1079 evas_object_smart_callback_add(wd->scr, "drag", _scr, obj);
1080 elm_widget_resize_object_set(obj, wd->scr);
1082 evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
1083 evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
1084 evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
1085 evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
1086 evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
1088 elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
1092 evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1093 evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1094 evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1095 evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1099 static Evas_Smart_Class sc;
1101 evas_object_smart_clipped_smart_set(&_pan_sc);
1103 sc.name = "elm_photocam_pan";
1104 sc.version = EVAS_SMART_CLASS_VERSION;
1107 sc.resize = _pan_resize;
1108 sc.move = _pan_move;
1109 sc.calculate = _pan_calculate;
1110 smart = evas_smart_class_new(&sc);
1114 wd->pan_smart = evas_object_smart_add(e, smart);
1115 wd->pan = evas_object_smart_data_get(wd->pan_smart);
1119 elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
1120 _pan_set, _pan_get, _pan_max_get,
1121 _pan_min_get, _pan_child_size_get);
1124 wd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
1128 wd->img = evas_object_image_add(e);
1129 evas_object_image_load_orientation_set(wd->img, EINA_TRUE);
1130 evas_object_image_scale_hint_set(wd->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
1131 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_DOWN,
1133 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_UP,
1135 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_MOVE,
1137 evas_object_image_scale_hint_set(wd->img, EVAS_IMAGE_SCALE_HINT_STATIC);
1138 evas_object_smart_member_add(wd->img, wd->pan_smart);
1139 elm_widget_sub_object_add(obj, wd->img);
1140 evas_object_image_filled_set(wd->img, 1);
1141 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_IMAGE_PRELOADED,
1142 _main_preloaded, obj);
1144 edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
1146 evas_object_size_hint_min_set(obj, minw, minh);
1148 evas_object_smart_callbacks_descriptions_set(obj, _signals);
1154 EAPI Evas_Load_Error
1155 elm_photocam_file_set(Evas_Object *obj, const char *file)
1157 ELM_CHECK_WIDTYPE(obj, widtype) EVAS_LOAD_ERROR_NONE;
1158 Widget_Data *wd = elm_widget_data_get(obj);
1160 if (!wd) return EVAS_LOAD_ERROR_GENERIC;
1161 if (!eina_stringshare_replace(&wd->file, file)) return EVAS_LOAD_ERROR_NONE;
1164 evas_object_hide(wd->img);
1165 evas_object_image_smooth_scale_set(wd->img, (wd->nosmooth == 0));
1166 evas_object_image_file_set(wd->img, NULL, NULL);
1167 evas_object_image_load_scale_down_set(wd->img, 0);
1168 evas_object_image_file_set(wd->img, wd->file, NULL);
1169 evas_object_image_size_get(wd->img, &w, &h);
1170 wd->do_region = evas_object_image_region_support_get(wd->img);
1173 wd->size.w = wd->size.imw / wd->zoom;
1174 wd->size.h = wd->size.imh / wd->zoom;
1175 if (wd->zoom_animator)
1178 if (wd->nosmooth == 0) _smooth_update(obj);
1179 ecore_animator_del(wd->zoom_animator);
1180 wd->zoom_animator = NULL;
1182 evas_object_image_file_set(wd->img, NULL, NULL);
1183 evas_object_image_load_scale_down_set(wd->img, 8);
1184 evas_object_image_file_set(wd->img, wd->file, NULL);
1185 evas_object_image_preload(wd->img, 0);
1186 wd->main_load_pending = 1;
1187 if (wd->calc_job) ecore_job_del(wd->calc_job);
1188 wd->calc_job = ecore_job_add(_calc_job, wd);
1189 evas_object_smart_callback_call(obj, SIG_LOAD, NULL);
1191 if (wd->preload_num == 1)
1193 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1194 "elm,state,busy,start", "elm");
1195 evas_object_smart_callback_call(obj, SIG_LOAD_DETAIL, NULL);
1198 double tz = wd->zoom;
1200 elm_photocam_zoom_set(wd->obj, tz);
1202 return evas_object_image_load_error_get(wd->img);
1206 elm_photocam_file_get(const Evas_Object *obj)
1208 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1209 Widget_Data *wd = elm_widget_data_get(obj);
1210 if (!wd) return NULL;
1215 elm_photocam_zoom_set(Evas_Object *obj, double zoom)
1217 ELM_CHECK_WIDTYPE(obj, widtype);
1218 Widget_Data *wd = elm_widget_data_get(obj);
1220 Grid *g, *g_zoom = NULL;
1221 Evas_Coord pw, ph, rx, ry, rw, rh;
1223 int zoom_changed = 0, started = 0;
1226 if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0);
1227 if (zoom == wd->zoom) return;
1229 wd->size.ow = wd->size.w;
1230 wd->size.oh = wd->size.h;
1231 elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
1232 elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
1233 if ((rw <= 0) || (rh <= 0)) return;
1235 if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
1237 wd->size.nw = (double)wd->size.imw / wd->zoom;
1238 wd->size.nh = (double)wd->size.imh / wd->zoom;
1240 else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT)
1242 if ((wd->size.imw < 1) || (wd->size.imh < 1))
1249 ph = (wd->size.imh * rw) / wd->size.imw;
1252 pw = (wd->size.imw * rh) / wd->size.imh;
1259 if (wd->size.imw > wd->size.imh)
1260 z = (double)wd->size.imw / pw;
1262 z = (double)wd->size.imh / ph;
1270 else if (wd->mode == ELM_PHOTOCAM_ZOOM_MODE_AUTO_FILL)
1272 if ((wd->size.imw < 1) || (wd->size.imh < 1))
1279 ph = (wd->size.imh * rw) / wd->size.imw;
1282 pw = (wd->size.imw * rh) / wd->size.imh;
1289 if (wd->size.imw > wd->size.imh)
1290 z = (double)wd->size.imw / pw;
1292 z = (double)wd->size.imh / ph;
1300 if (wd->main_load_pending)
1302 wd->size.w = wd->size.nw;
1303 wd->size.h = wd->size.nh;
1306 EINA_LIST_FOREACH(wd->grids, l, g)
1308 if (g->zoom == grid_zoom_calc(wd->zoom))
1310 wd->grids = eina_list_remove(wd->grids, g);
1311 wd->grids = eina_list_prepend(wd->grids, g);
1316 g = grid_create(obj);
1319 if (eina_list_count(wd->grids) > 1)
1321 g_zoom = eina_list_last(wd->grids)->data;
1322 wd->grids = eina_list_remove(wd->grids, g_zoom);
1323 grid_clear(obj, g_zoom);
1325 EINA_LIST_FOREACH(wd->grids, l, g_zoom)
1330 wd->grids = eina_list_prepend(wd->grids, g);
1334 EINA_LIST_FREE(wd->grids, g)
1341 wd->t_start = ecore_loop_time_get();
1342 wd->t_end = wd->t_start + _elm_config->zoom_friction;
1343 if ((wd->size.w > 0) && (wd->size.h > 0))
1345 wd->size.spos.x = (double)(rx + (rw / 2)) / (double)wd->size.w;
1346 wd->size.spos.y = (double)(ry + (rh / 2)) / (double)wd->size.h;
1350 wd->size.spos.x = 0.5;
1351 wd->size.spos.y = 0.5;
1353 if (rw > wd->size.w) wd->size.spos.x = 0.5;
1354 if (rh > wd->size.h) wd->size.spos.y = 0.5;
1355 if (wd->size.spos.x > 1.0) wd->size.spos.x = 1.0;
1356 if (wd->size.spos.y > 1.0) wd->size.spos.y = 1.0;
1363 if (!wd->zoom_animator)
1365 wd->zoom_animator = ecore_animator_add(_zoom_anim, obj);
1367 if (wd->nosmooth == 1) _smooth_update(obj);
1371 an = wd->zoom_animator;
1374 if (!_zoom_anim(obj))
1376 ecore_animator_del(an);
1380 if (wd->calc_job) ecore_job_del(wd->calc_job);
1381 wd->calc_job = ecore_job_add(_calc_job, wd);
1385 evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL);
1387 evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1390 evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL);
1394 elm_photocam_zoom_get(const Evas_Object *obj)
1396 ELM_CHECK_WIDTYPE(obj, widtype) 1.0;
1397 Widget_Data *wd = elm_widget_data_get(obj);
1398 if (!wd) return 1.0;
1403 elm_photocam_zoom_mode_set(Evas_Object *obj, Elm_Photocam_Zoom_Mode mode)
1405 ELM_CHECK_WIDTYPE(obj, widtype);
1406 Widget_Data *wd = elm_widget_data_get(obj);
1408 if (wd->mode == mode) return;
1411 double tz = wd->zoom;
1413 elm_photocam_zoom_set(wd->obj, tz);
1417 EAPI Elm_Photocam_Zoom_Mode
1418 elm_photocam_zoom_mode_get(const Evas_Object *obj)
1420 ELM_CHECK_WIDTYPE(obj, widtype) ELM_PHOTOCAM_ZOOM_MODE_LAST;
1421 Widget_Data *wd = elm_widget_data_get(obj);
1422 if (!wd) return ELM_PHOTOCAM_ZOOM_MODE_LAST;
1427 elm_photocam_image_size_get(const Evas_Object *obj, int *w, int *h)
1429 ELM_CHECK_WIDTYPE(obj, widtype);
1430 Widget_Data *wd = elm_widget_data_get(obj);
1432 if (w) *w = wd->size.imw;
1433 if (h) *h = wd->size.imh;
1437 elm_photocam_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h)
1439 ELM_CHECK_WIDTYPE(obj, widtype);
1440 Widget_Data *wd = elm_widget_data_get(obj);
1441 Evas_Coord sx, sy, sw, sh;
1443 elm_smart_scroller_child_pos_get(wd->scr, &sx, &sy);
1444 elm_smart_scroller_child_viewport_size_get(wd->scr, &sw, &sh);
1449 *x = (wd->size.imw * sx) / wd->size.w;
1450 if (*x > wd->size.imw) *x = wd->size.imw;
1454 *w = (wd->size.imw * sw) / wd->size.w;
1455 if (*w > wd->size.imw) *w = wd->size.imw;
1456 else if (*w < 0) *w = 0;
1469 *y = (wd->size.imh * sy) / wd->size.h;
1470 if (*y > wd->size.imh) *y = wd->size.imh;
1474 *h = (wd->size.imh * sh) / wd->size.h;
1475 if (*h > wd->size.imh) *h = wd->size.imh;
1476 else if (*h < 0) *h = 0;
1487 elm_photocam_image_region_show(Evas_Object *obj, int x, int y, int w, int h __UNUSED__)
1489 ELM_CHECK_WIDTYPE(obj, widtype);
1490 Widget_Data *wd = elm_widget_data_get(obj);
1493 if ((wd->size.imw < 1) || (wd->size.imh < 1)) return;
1494 rx = (x * wd->size.w) / wd->size.imw;
1495 ry = (y * wd->size.h) / wd->size.imh;
1496 rw = (w * wd->size.w) / wd->size.imw;
1497 rh = (h * wd->size.h) / wd->size.imh;
1500 if ((rx + rw) > wd->size.w) rx = wd->size.w - rw;
1501 if ((ry + rh) > wd->size.h) ry = wd->size.h - rh;
1502 if (wd->zoom_animator)
1505 ecore_animator_del(wd->zoom_animator);
1506 wd->zoom_animator = NULL;
1508 evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1510 elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh);
1514 elm_photocam_image_region_bring_in(Evas_Object *obj, int x, int y, int w, int h __UNUSED__)
1516 ELM_CHECK_WIDTYPE(obj, widtype);
1517 Widget_Data *wd = elm_widget_data_get(obj);
1520 if ((wd->size.imw < 1) || (wd->size.imh < 1)) return;
1521 rx = (x * wd->size.w) / wd->size.imw;
1522 ry = (y * wd->size.h) / wd->size.imh;
1523 rw = (w * wd->size.w) / wd->size.imw;
1524 rh = (h * wd->size.h) / wd->size.imh;
1527 if ((rx + rw) > wd->size.w) rx = wd->size.w - rw;
1528 if ((ry + rh) > wd->size.h) ry = wd->size.h - rh;
1529 if (wd->zoom_animator)
1532 if (!wd->nosmooth) _smooth_update(obj);
1533 ecore_animator_del(wd->zoom_animator);
1534 wd->zoom_animator = NULL;
1536 evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1538 elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh);
1542 elm_photocam_paused_set(Evas_Object *obj, Eina_Bool paused)
1544 ELM_CHECK_WIDTYPE(obj, widtype);
1545 Widget_Data *wd = elm_widget_data_get(obj);
1547 if (wd->paused == !!paused) return;
1548 wd->paused = paused;
1551 if (wd->zoom_animator)
1553 ecore_animator_del(wd->zoom_animator);
1554 wd->zoom_animator = NULL;
1556 evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1562 elm_photocam_paused_get(const Evas_Object *obj)
1564 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1565 Widget_Data *wd = elm_widget_data_get(obj);
1566 if (!wd) return EINA_FALSE;
1571 elm_photocam_internal_image_get(const Evas_Object *obj)
1573 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1574 Widget_Data *wd = elm_widget_data_get(obj);
1575 if (!wd) return NULL;
1580 elm_photocam_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1582 ELM_CHECK_WIDTYPE(obj, widtype);
1583 Widget_Data *wd = elm_widget_data_get(obj);
1585 elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
1589 elm_photocam_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
1591 ELM_CHECK_WIDTYPE(obj, widtype);
1592 Widget_Data *wd = elm_widget_data_get(obj);
1594 elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);