ef020a13f44948084a93a1f87e4dc7fea59aa993
[framework/uifw/elementary.git] / src / lib / elm_map.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_module_priv.h"
4
5 /**
6  * @defgroup Map Map
7  * @ingroup Elementary
8  *
9  * This is a widget specifically for displaying the free map OpenStreetMap.
10  *
11  * Signals that you can add callbacks for are:
12  *
13  * clicked - This is called when a user has clicked the map without dragging
14  * around.
15  *
16  * press - This is called when a user has pressed down on the map.
17  *
18  * longpressed - This is called when a user has pressed down on the map for
19  * a long time without dragging around.
20  *
21  * clicked,double - This is called when a user has double-clicked the photo.
22  *
23  * load,details - Map detailed data load begins.
24  *
25  * loaded,details - This is called when all parts of the map are loaded.
26  *
27  * zoom,start - Zoom animation started.
28  *
29  * zoom,stop - Zoom animation stopped.
30  *
31  * zoom,change - Zoom changed when using an auto zoom mode.
32  *
33  * scroll - the content has been scrolled (moved)
34  *
35  * scroll,anim,start - scrolling animation has started
36  *
37  * scroll,anim,stop - scrolling animation has stopped
38  *
39  * scroll,drag,start - dragging the contents around has started
40  *
41  * scroll,drag,stop - dragging the contents around has stopped
42  *
43  * TODO : doxygen
44  */
45
46
47 typedef struct _Widget_Data Widget_Data;
48 typedef struct _Pan Pan;
49 typedef struct _Grid Grid;
50 typedef struct _Grid_Item Grid_Item;
51 typedef struct _Marker_Group Marker_Group;
52 typedef struct _Mod_Api Mod_Api;
53
54 #define DEST_DIR_ZOOM_PATH "/tmp/elm_map/%d/%d/"
55 #define DEST_DIR_PATH DEST_DIR_ZOOM_PATH"%d/"
56 #define DEST_FILE_PATH "%s%d.png"
57
58 // Map sources
59 // Currently the size of a tile must be 256*256
60 // and the size of the map must be pow(2.0, z)*tile_size
61 typedef struct _Map_Sources_Tab
62 {
63    Elm_Map_Sources source;
64    const char *name;
65    int zoom_min;
66    int zoom_max;
67    ElmMapSourceURLFunc url_cb;
68    Eina_Bool use_module : 1;
69 } Map_Sources_Tab;
70
71 #define ZOOM_MAX 20
72 #define TOUCH_HOLD_RANGE 40
73 //Zemm min is supposed to be 0
74 static char * _mapnik_url_cb(void *data ,int x, int y, int zoom);
75 static char * _osmarender_url_cb(void *data ,int x, int y, int zoom);
76 static char * _cyclemap_url_cb(void *data ,int x, int y, int zoom);
77 static char * _maplint_url_cb(void *data ,int x, int y, int zoom);
78 static char * _decarta_url_cb(void *data ,int x, int y, int zoom);
79 static Map_Sources_Tab map_sources_tab[] =
80 {
81      {ELM_MAP_SOURCE_MAPNIK, "Mapnik", 0, 18, _mapnik_url_cb, EINA_FALSE},
82      {ELM_MAP_SOURCE_OSMARENDER, "Osmarender", 0, 17, _osmarender_url_cb, EINA_FALSE},
83      {ELM_MAP_SOURCE_CYCLEMAP, "Cycle Map", 0, 17, _cyclemap_url_cb, EINA_FALSE},
84      {ELM_MAP_SOURCE_MAPLINT, "Maplint", 12, 16, _maplint_url_cb, EINA_FALSE},
85      {ELM_MAP_SOURCE_DECARTA, "Decarta", 1, 20, _decarta_url_cb, EINA_TRUE},
86      {ELM_MAP_SOURCE_CUSTOM_1, "Custom 1", 0, 18, NULL, EINA_FALSE},
87      {ELM_MAP_SOURCE_CUSTOM_2, "Custom 2", 0, 18, NULL, EINA_FALSE},
88      {ELM_MAP_SOURCE_CUSTOM_3, "Custom 3", 0, 18, NULL, EINA_FALSE},
89      {ELM_MAP_SOURCE_CUSTOM_4, "Custom 4", 0, 18, NULL, EINA_FALSE},
90      {ELM_MAP_SOURCE_CUSTOM_5, "Custom 5", 0, 18, NULL, EINA_FALSE},
91      {ELM_MAP_SOURCE_CUSTOM_6, "Custom 6", 0, 18, NULL, EINA_FALSE}
92 };
93
94 struct _Elm_Map_Marker_Class
95 {
96    const char *style;
97    int zoom_displayed;
98
99    struct _Elm_Map_Marker_Class_Func {
100       ElmMapMarkerGetFunc get;
101       ElmMapMarkerDelFunc del; //if NULL the object will be destroyed with evas_object_del()
102       ElmMapMarkerIconGetFunc icon_get;
103    } func;
104
105    struct { //this part is private, do not modify these values
106       Eina_Bool set : 1;
107       Evas_Coord edje_w, edje_h;
108    } priv;
109 };
110
111 struct _Elm_Map_Marker
112 {
113    Widget_Data *wd;
114    Elm_Map_Marker_Class *clas;
115    Elm_Map_Group_Class *clas_group;
116    double longitude, latitude;
117
118    Evas_Coord map_size;
119    Evas_Coord x[ZOOM_MAX+1], y[ZOOM_MAX+1];
120    void *data;
121
122    Marker_Group *groups[ZOOM_MAX+1];
123
124    Evas_Object *content;
125 };
126
127 struct _Elm_Map_Group_Class
128 {
129    const char *style;
130    void *data;
131    int zoom_displayed; // display the group if the zoom is >= to zoom_display
132    int zoom_grouped; // group the markers only if the zoom is <= to zoom_groups
133    Eina_Bool hide : 1;
134
135    struct {
136       ElmMapGroupIconGetFunc icon_get;
137    } func;
138    
139    struct { //this part is private, do not modify these values
140       Eina_Bool set : 1;
141       Evas_Coord edje_w, edje_h;
142       Evas_Coord edje_max_w, edje_max_h;
143       
144       Eina_List *objs_used;
145       Eina_List *objs_notused;
146    } priv;
147 };
148
149 struct _Marker_Group
150 {
151    Widget_Data *wd;
152    Eina_Matrixsparse_Cell *cell;
153    Elm_Map_Group_Class *clas;
154
155    Eina_List *markers;
156    long long sum_x, sum_y;
157    Evas_Coord x, y;
158    Evas_Coord w, h;
159
160    Evas_Object *obj, *bubble, *sc, *bx, *rect;
161    Eina_Bool open : 1;
162    Eina_Bool bringin : 1;
163    Eina_Bool update_nbelems : 1;
164    Eina_Bool update_resize : 1;
165    Eina_Bool update_raise : 1;
166    Eina_Bool delete_object : 1;
167 };
168
169 struct _Grid_Item
170 {
171    Widget_Data *wd;
172    Evas_Object *img;
173    //Evas_Object *txt;
174    const char *file;
175    struct {
176       int x, y, w, h;
177    } src, out;
178    Eina_Bool want : 1;
179    Eina_Bool download : 1;
180    Eina_Bool have : 1;
181    Ecore_File_Download_Job *job;
182    int try_num;
183 };
184
185 struct _Grid
186 {
187    Widget_Data *wd;
188    int tsize; // size of tile (tsize x tsize pixels)
189    int zoom; // zoom level tiles want for optimal display (1, 2, 4, 8)
190    int iw, ih; // size of image in pixels
191    int w, h; // size of grid image in pixels (represented by grid)
192    int gw, gh; // size of grid in tiles
193    Eina_Matrixsparse *grid;
194 };
195
196 struct _Widget_Data
197 {
198    Evas_Object *obj;
199    Evas_Object *scr;
200    Evas_Object *pan_smart;
201    Evas_Object *rect;
202    Evas_Object *sep_maps_markers; //map objects are below this object and marker objects are on top
203    Pan *pan;
204    Evas_Coord pan_x, pan_y, minw, minh;
205
206    int id;
207    int zoom;
208    Elm_Map_Zoom_Mode mode;
209
210    Ecore_Job *calc_job;
211    Ecore_Timer *scr_timer;
212    Ecore_Timer *long_timer;
213    Ecore_Animator *zoom_animator;
214    double t_start, t_end;
215    struct {
216       int w, h;
217       int ow, oh, nw, nh;
218       struct {
219          double x, y;
220       } spos;
221    } size;
222    struct {
223       Eina_Bool show : 1;
224       Evas_Coord x, y ,w ,h;
225    } show;
226    int tsize;
227    int nosmooth;
228    int preload_num;
229    Eina_List *grids;
230    Eina_Bool resized : 1;
231    Eina_Bool longpressed : 1;
232    Eina_Bool on_hold : 1;
233    Eina_Bool paused : 1;
234    Eina_Bool paused_markers : 1;
235    Eina_Bool pinch_zoom : 1;
236    
237    struct {
238       Eina_Bool enabled;
239       double lon, lat;
240    } center_on;
241
242    Ecore_Job *markers_place_job;
243    Eina_Matrixsparse *markers[ZOOM_MAX+1];
244    Eina_List *cells_displayed; // list of Eina_Matrixsparse_Cell
245    Evas_Coord markers_max_num;
246    int marker_max_w, marker_max_h;
247    int marker_zoom;
248    Eina_List *opened_bubbles; //opened bubbles, list of Map_Group *
249
250    Eina_List *groups_clas; // list of Elm_Map_Group_Class*
251    Eina_List *markers_clas; // list of Elm_Map_Markers_Class*
252
253    Elm_Map_Sources source;
254    Mod_Api *api;
255 };
256
257 struct _Pan
258 {
259    Evas_Object_Smart_Clipped_Data __clipped_data;
260    Widget_Data *wd;
261 };
262
263 struct _Mod_Api
264 {
265    Eina_Bool (*obj_hook) (Evas_Object *obj);
266    Eina_Bool (*obj_unhook) (Evas_Object *obj);
267    char * (*obj_url_request) (Evas_Object *obj, int x, int y, int zoom);
268    Eina_Bool (*obj_convert_coord_into_geo) (const Evas_Object *obj, int zoom, int x, int y, int size, double *lon, double *lat);
269    Eina_Bool (*obj_convert_geo_into_coord) (const Evas_Object *obj, int zoom, double lon, double lat, int size, int *x, int *y);
270 };
271
272 struct event_t
273 {
274    int device;
275    
276    struct prev {
277    Evas_Coord x, y;
278    } prev;
279    
280    Evas_Coord x, y, w, h;
281    
282    Evas_Object *object;
283    Ecore_Timer *hold_timer;
284    
285    int ts;
286    int v;
287    
288    int pinch_dis;
289    Evas_Object *pinch_obj;
290    Evas_Object *test;
291 };
292 static int dis_old = 0;
293 static Eina_List *s_event_list;
294
295 static const char *widtype = NULL;
296
297 static const char SIG_CHANGED[] = "changed";
298 static const char SIG_CLICKED[] = "clicked";
299 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
300 static const char SIG_LOADED_DETAIL[] = "loaded,detail";
301 static const char SIG_LOAD_DETAIL[] = "load,detail";
302 static const char SIG_LONGPRESSED[] = "longpressed";
303 static const char SIG_PRESS[] = "press";
304 static const char SIG_SCROLL[] = "scroll";
305 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
306 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
307 static const char SIG_ZOOM_CHANGE[] = "zoom,change";
308 static const char SIG_ZOOM_START[] = "zoom,start";
309 static const char SIG_ZOOM_STOP[] = "zoom,stop";
310 static const Evas_Smart_Cb_Description _signals[] = {
311   {SIG_CHANGED, ""},
312   {SIG_CLICKED, ""},
313   {SIG_CLICKED_DOUBLE, ""},
314   {SIG_LOADED_DETAIL, ""},
315   {SIG_LOAD_DETAIL, ""},
316   {SIG_LONGPRESSED, ""},
317   {SIG_PRESS, ""},
318   {SIG_SCROLL, ""},
319   {SIG_SCROLL_DRAG_START, ""},
320   {SIG_SCROLL_DRAG_STOP, ""},
321   {SIG_ZOOM_CHANGE, ""},
322   {SIG_ZOOM_START, ""},
323   {SIG_ZOOM_STOP, ""},
324   {NULL, NULL}
325 };
326
327 static void _pan_calculate(Evas_Object *obj);
328
329 static void _del_hook(Evas_Object *obj);
330 static void _theme_hook(Evas_Object *obj);
331 static void _sizing_eval(Evas_Object *obj);
332 static void _calc_job(void *data);
333 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);
334 static void grid_clear(Evas_Object *obj, Grid *g);
335 static Grid *grid_create(Evas_Object *obj);
336 static void grid_load(Evas_Object *obj, Grid *g);
337
338
339 static void _group_object_create(Marker_Group *group);
340 static void _group_object_free(Marker_Group *group);
341 static void _group_open_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
342 static void _group_bringin_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
343 static void _group_bubble_create(Marker_Group *group);
344 static void _group_bubble_free(Marker_Group *group);
345 static void _group_bubble_place(Marker_Group *group);
346
347 static int _group_bubble_content_update(Marker_Group *group);
348 static void _group_bubble_content_free(Marker_Group *group);
349 static void marker_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh);
350 static void _bubble_sc_hits_changed_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
351
352 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
353 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
354 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
355
356 static void _mouse_multi_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
357 static void _mouse_multi_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
358 static void _mouse_multi_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
359
360 static Eina_Bool
361 hold_timer_cb(void *data)
362 {
363    struct event_t *ev0 = (struct event_t *)data;
364    ev0->hold_timer = NULL;
365
366    return ECORE_CALLBACK_CANCEL;
367 }
368
369 static void 
370 _rect_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
371 {
372    Widget_Data *wd = elm_widget_data_get(data);
373    int x,y,w,h;
374
375    evas_object_geometry_get(wd->rect,&x,&y,&w,&h);
376    evas_object_geometry_get(wd->pan_smart,&x,&y,&w,&h);
377    evas_object_resize(wd->rect,w,h);
378    evas_object_move(wd->rect,x,y);
379 }
380
381 static int
382 get_multi_device(void)
383 {
384    Eina_List *l;
385    struct event_t *ev = NULL;
386    
387    EINA_LIST_FOREACH(s_event_list, l, ev) {
388       if(ev->device != 0) return ev->device;                            
389    }
390    return 0;
391 }
392
393 static int
394 get_distance(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
395 {
396    int dis, dx, dy;
397    
398    dx = x1 - x2;
399    dy = y1 - y2;
400    
401    dis = (int)sqrt(dx * dx + dy  * dy);
402    return dis;
403 }
404
405 static struct event_t*
406 get_event_object(int device)
407 {
408    Eina_List *l;
409    struct event_t *ev = NULL;
410    
411    EINA_LIST_FOREACH(s_event_list, l, ev) {
412       if(ev->device == device) break;
413       ev = NULL;
414    }
415    return ev;
416 }
417
418 static struct event_t *
419 create_event_object(Evas_Object *object, int device)
420 {
421    struct event_t *ev;
422
423    ev = calloc(1, sizeof(struct event_t));
424    if(ev == NULL) DBG("Cannot allocate event_t");
425    
426    ev->object = object;
427    ev->device = device;
428    
429    evas_object_geometry_get(object, &ev->x, &ev->y, &ev->w, &ev->h);
430    
431    s_event_list = eina_list_append(s_event_list, ev);
432    
433    return ev;
434 }
435
436 static void
437 destroy_event_object(struct event_t *ev)
438 {
439    if(ev == NULL) return;
440    ev->pinch_obj = NULL;
441    ev->pinch_dis = 0;
442    
443    s_event_list = eina_list_remove(s_event_list, ev);
444    
445    if (ev->hold_timer) {
446       ecore_timer_del(ev->hold_timer);
447       ev->hold_timer = NULL;
448    }
449    free(ev);
450 }
451
452 static Mod_Api *
453 module(Evas_Object *obj __UNUSED__)
454 {
455    static Elm_Module *m = NULL;
456    if (m) goto ok; // already found - just use
457    if (!(m = _elm_module_find_as("map/api"))) return NULL;
458
459    // get module api
460    m->api = malloc(sizeof(Mod_Api));
461    if (!m->api) return NULL;
462    ((Mod_Api *)(m->api)      )->obj_hook = // called on creation
463      _elm_module_symbol_get(m, "obj_hook");
464    ((Mod_Api *)(m->api)      )->obj_unhook = // called on deletion
465      _elm_module_symbol_get(m, "obj_unhook");
466    ((Mod_Api *)(m->api)      )->obj_url_request =
467      _elm_module_symbol_get(m, "obj_url_request");
468    ((Mod_Api *)(m->api)      )->obj_convert_coord_into_geo =
469      _elm_module_symbol_get(m, "obj_convert_coord_into_geo");
470    ((Mod_Api *)(m->api)      )->obj_convert_geo_into_coord =
471      _elm_module_symbol_get(m, "obj_convert_geo_into_coord");
472    ok: // ok - return api
473    return m->api;
474 }
475
476 static void
477 rect_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
478 {
479    Widget_Data *wd = elm_widget_data_get(obj);
480    Evas_Coord ax, ay, gw, gh, hh, ww;
481    if (!wd) return;
482    evas_object_geometry_get(wd->rect, NULL, NULL, &ww, &hh);
483
484    ax = 0;
485    ay = 0;
486    gw = wd->size.w;
487    gh = wd->size.h;
488
489    if (ww == gw && hh == gh) return;
490
491    if (ow > gw) ax = (ow - gw) / 2;
492    if (oh > gh) ay = (oh - gh) / 2;
493    evas_object_move(wd->rect,
494                     ox + 0 - px + ax,
495                     oy + 0 - py + ay);
496    evas_object_resize(wd->rect, gw, gh);
497    
498    if (wd->show.show)
499      {
500         wd->show.show = EINA_FALSE;
501         elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h);
502      }
503 }
504
505 static void
506 marker_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
507 {
508    Widget_Data *wd = elm_widget_data_get(obj);
509    Evas_Coord ax, ay, gw, gh, tx, ty;
510    Eina_List *l, *markers;
511    Eina_Matrixsparse_Cell *cell;
512    Marker_Group *group;
513    int xx, yy, ww, hh;
514    char buf[PATH_MAX];
515    int y, x;
516    int g_xx, g_yy, g_hh, g_ww;
517
518    if (!wd) return;
519    if (g != eina_list_data_get(wd->grids)) return;
520
521    ax = 0;
522    ay = 0;
523    gw = wd->size.w;
524    gh = wd->size.h;
525    if (ow > gw) ax = (ow - gw) / 2;
526    if (oh > gh) ay = (oh - gh) / 2;
527
528    if (wd->zoom != wd->marker_zoom)
529      {
530         EINA_LIST_FREE(wd->cells_displayed, cell)
531           {
532              EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
533                {
534                   if (group->obj) _group_object_free(group);
535                }
536           }
537      }
538    wd->marker_zoom = wd->zoom;
539
540    if (wd->paused_markers
541        && (wd->size.nw != wd->size.w || wd->size.nh != wd->size.h) )
542      return;
543
544    g_xx = wd->pan_x / wd->tsize;
545    if (g_xx < 0) g_xx = 0;
546    g_yy = wd->pan_y / wd->tsize;
547    if (g_yy < 0) g_yy = 0;
548    g_ww =  ow / wd->tsize + 1;
549    if (g_xx + g_ww >= g->gw) g_ww = g->gw - g_xx - 1;
550    g_hh =  oh / wd->tsize + 1;
551    if (g_yy + g_hh >= g->gh) g_hh = g->gh - g_yy - 1;
552
553    //hide groups no more displayed
554    EINA_LIST_FREE(wd->cells_displayed, cell)
555      {
556         eina_matrixsparse_cell_position_get(cell, (unsigned long *)&y, (unsigned long *)&x);
557         if (y < g_yy || y > g_yy + g_hh || x < g_xx || x > g_xx + g_ww)
558           {
559              EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
560                {
561                   if (group->obj) _group_object_free(group);
562                }
563           }
564      }
565
566    for (y = g_yy; y <= g_yy + g_hh; y++)
567      {
568         for (x = g_xx; x <= g_xx + g_ww; x++)
569           {
570              if (!wd->markers[wd->zoom]) continue;
571              eina_matrixsparse_cell_idx_get(wd->markers[wd->zoom], y, x, &cell);
572              if (!cell) continue;
573              wd->cells_displayed = eina_list_append(wd->cells_displayed, cell);
574              markers = eina_matrixsparse_cell_data_get(cell);
575              EINA_LIST_FOREACH(markers, l, group)
576                {
577                   if (!group->markers) continue;
578                   if (group->clas->zoom_displayed > wd->zoom) continue;
579
580                   xx = group->x;
581                   yy = group->y;
582                   ww = group->w;
583                   hh = group->h;
584
585                   if (eina_list_count(group->markers) == 1)
586                     {
587                        Elm_Map_Marker *m = eina_list_data_get(group->markers);
588                        ww = m->clas->priv.edje_w;
589                        hh = m->clas->priv.edje_h;
590                     }
591
592                   if (ww <= 0) ww = 1;
593                   if (hh <= 0) hh = 1;
594
595                   if ((gw != g->w) && (g->w > 0))
596                     {
597                        tx = xx;
598                        xx = ((long long )gw * xx) / g->w;
599                        ww = (((long long)gw * (tx + ww)) / g->w) - xx;
600                     }
601                   if ((gh != g->h) && (g->h > 0))
602                     {
603                        ty = yy;
604                        yy = ((long long)gh * yy) / g->h;
605                        hh = (((long long)gh * (ty + hh)) / g->h) - yy;
606                     }
607
608                   if (!group->clas->hide
609                       && xx-px+ax+ox >= ox && xx-px+ax+ox<= ox+ow
610                       && yy-py+ay+oy >= oy && yy-py+ay+oy<= oy+oh)
611                     {
612                        if (!group->obj) _group_object_create(group);
613
614                        if (group->update_nbelems)
615                          {
616                             group->update_nbelems = EINA_FALSE;
617                             if (eina_list_count(group->markers) > 1)
618                               {
619                                  snprintf(buf, sizeof(buf), "%d", eina_list_count(group->markers));
620                                  edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", buf);
621                               }
622                             else
623                               edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", "");
624                          }
625                        evas_object_move(group->obj,
626                                         xx - px + ax + ox - ww/2,
627                                         yy - py + ay + oy - hh/2);
628                        if (!wd->paused_markers || group->update_resize)
629                          {
630                             group->update_resize = EINA_FALSE;
631                             evas_object_resize(group->obj, ww, hh);
632                          }
633                        if (group->update_raise)
634                          {
635                             group->update_raise = EINA_FALSE;
636                             evas_object_raise(group->obj);
637                             evas_object_show(group->obj);
638                          }
639                        if (group->bubble) _group_bubble_place(group);
640                     }
641                   else if (group->obj)
642                     {
643                        _group_object_free(group);
644                     }
645                }
646           }
647      }
648 }
649
650 static void
651 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)
652 {
653    Widget_Data *wd = elm_widget_data_get(obj);
654    Evas_Coord ax, ay, gw, gh, tx, ty;
655    int xx, yy, ww, hh;
656
657    if (!wd) return;
658    
659    ax = 0;
660    ay = 0;
661    gw = wd->size.w;
662    gh = wd->size.h;
663    if (ow > gw) ax = (ow - gw) / 2;
664    if (oh > gh) ay = (oh - gh) / 2;
665
666    Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
667    Eina_Matrixsparse_Cell *cell;
668
669    EINA_ITERATOR_FOREACH(it, cell)
670      {
671         Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
672
673         xx = gi->out.x;
674         yy = gi->out.y;
675         ww = gi->out.w;
676         hh = gi->out.h;
677         if ((gw != g->w) && (g->w > 0))
678           {
679              tx = xx;
680              xx = ((long long )gw * xx) / g->w;
681              ww = (((long long)gw * (tx + ww)) / g->w) - xx;
682           }
683         if ((gh != g->h) && (g->h > 0))
684           {
685              ty = yy;
686              yy = ((long long)gh * yy) / g->h;
687              hh = (((long long)gh * (ty + hh)) / g->h) - yy;
688           }
689         evas_object_move(gi->img,
690                          xx - px + ax + ox,
691                          yy - py + ay + oy);
692         
693         evas_object_resize(gi->img, ww, hh);
694
695         /*evas_object_move(gi->txt,
696           xx - px + ax + ox,
697           yy - py + ay + oy);
698
699           evas_object_resize(gi->txt, ww, hh);
700           */
701      }
702    eina_iterator_free(it);
703 }
704
705 static void
706 grid_clear(Evas_Object *obj, Grid *g)
707 {
708    Widget_Data *wd = elm_widget_data_get(obj);
709    char buf[PATH_MAX];
710
711    if (!wd) return;
712    if (!g->grid) return;
713
714    Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
715    Eina_Matrixsparse_Cell *cell;
716
717    snprintf(buf, sizeof(buf), DEST_DIR_ZOOM_PATH, wd->id, g->zoom);
718    ecore_file_recursive_rm(buf);
719
720    EINA_ITERATOR_FOREACH(it, cell)
721      {
722         Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
723         evas_object_del(gi->img);
724         //evas_object_del(gi->txt);
725
726         if (gi->want)
727           {
728              gi->want = EINA_FALSE;
729              wd->preload_num--;
730              if (wd->preload_num == 0)
731                {
732                   edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
733                         "elm,state,busy,stop", "elm");
734                   evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
735                }
736           }
737
738         if (gi->job)
739           {
740              DBG("DOWNLOAD abort %s", gi->file);
741              ecore_file_download_abort(gi->job);
742              ecore_file_remove(gi->file);
743              gi->job = NULL;
744           }
745         if (gi->file)
746           eina_stringshare_del(gi->file);
747         
748         free(gi);
749      }
750    eina_matrixsparse_free(g->grid);
751    eina_iterator_free(it);
752    g->grid = NULL;
753    g->gw = 0;
754    g->gh = 0;
755 }
756
757 static void
758 _tile_update(Grid_Item *gi)
759 {
760    gi->want = EINA_FALSE;
761    gi->download = EINA_FALSE;
762    evas_object_image_file_set(gi->img, gi->file, NULL);
763    if (evas_object_image_load_error_get(gi->img) != EVAS_LOAD_ERROR_NONE)
764      ecore_file_remove(gi->file);
765    
766    evas_object_show(gi->img);
767
768    //evas_object_text_text_set(gi->txt, gi->file);
769    //evas_object_show(gi->txt);
770
771    gi->have = EINA_TRUE;
772    gi->wd->preload_num--;
773    if (gi->wd->preload_num == 0)
774      {
775         edje_object_signal_emit(elm_smart_scroller_edje_object_get(gi->wd->scr),
776                                 "elm,state,busy,stop", "elm");
777         evas_object_smart_callback_call(gi->wd->obj, SIG_LOADED_DETAIL, NULL);
778      }
779 }
780
781
782 static void
783 _tile_downloaded(void *data, const char *file __UNUSED__, int status)
784 {
785    Grid_Item *gi = data;
786
787    gi->download = EINA_FALSE;
788    gi->job = NULL;
789
790    DBG("DOWNLOAD done %s", gi->file);
791    if (gi->want && !status) _tile_update(gi);
792
793    if (status)
794      {
795         DBG("Download failed %s (%d) ", gi->file, status);
796         ecore_file_remove(gi->file);
797      }
798 }
799
800 static Grid *
801 grid_create(Evas_Object *obj)
802 {
803    Widget_Data *wd = elm_widget_data_get(obj);
804    Grid *g;
805
806    g = calloc(1, sizeof(Grid));
807
808    g->zoom = wd->zoom;
809    g->tsize = wd->tsize;
810    g->wd = wd;
811
812    if (g->zoom > map_sources_tab[wd->source].zoom_max) return NULL;
813    if (g->zoom < map_sources_tab[wd->source].zoom_min) return NULL;
814
815    int size =  pow(2.0, wd->zoom);
816    g->gw = size;
817    g->gh = size;
818
819    g->w = g->tsize * g->gw;
820    g->h = g->tsize * g->gh;
821
822    g->grid = eina_matrixsparse_new(g->gh, g->gw, NULL, NULL);
823
824    return g;
825 }
826
827 static void
828 grid_load(Evas_Object *obj, Grid *g)
829 {
830    Widget_Data *wd = elm_widget_data_get(obj);
831    int x, y;
832    int size;
833    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, tx, ty, gw, gh, xx, yy, ww, hh;
834    Eina_Iterator *it;
835    Eina_Matrixsparse_Cell *cell;
836    Grid_Item *gi;
837
838    if (!wd) return;
839    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
840    evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
841                                
842    gw = wd->size.w;
843    gh = wd->size.h;
844
845    if ((gw <= 0) || (gh <= 0)) return;
846
847    size = g->tsize;
848    if ((gw != g->w) && (g->w > 0))
849      size = ((long long)gw * size) / g->w;
850    if (size < (g->tsize / 2)) return; // else we will load to much tiles
851
852    it = eina_matrixsparse_iterator_new(g->grid);
853    
854    EINA_ITERATOR_FOREACH(it, cell)
855      {
856         gi = eina_matrixsparse_cell_data_get(cell);
857
858         xx = gi->out.x;
859         yy = gi->out.y;
860         ww = gi->out.w;
861         hh = gi->out.h;
862
863         if ((gw != g->w) && (g->w > 0))
864           {
865              tx = xx;
866              xx = ((long long )gw * xx) / g->w;
867              ww = (((long long)gw * (tx + ww)) / g->w) - xx;
868           }
869         if ((gh != g->h) && (g->h > 0))
870           {
871              ty = yy;
872              yy = ((long long)gh * yy) / g->h;
873              hh = (((long long)gh * (ty + hh)) / g->h) - yy;
874           }
875
876         if (!ELM_RECTS_INTERSECT(xx - wd->pan_x + ox, 
877                                  yy  - wd->pan_y + oy,
878                                  ww, hh,
879                                  cvx, cvy, cvw, cvh))
880           {
881              if (gi->want)
882                {
883                   wd->preload_num--;
884                   if (wd->preload_num == 0)
885                     {
886                        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
887                                                "elm,state,busy,stop", "elm");
888                        evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL,
889                                                        NULL);
890                     }
891                   evas_object_hide(gi->img);
892                   //evas_object_hide(gi->txt);
893                   evas_object_image_file_set(gi->img, NULL, NULL);
894                   gi->want = EINA_FALSE;
895                   gi->have = EINA_FALSE;
896                   
897                   if (gi->job)
898                     {
899                        DBG("DOWNLOAD abort %s", gi->file);
900                        ecore_file_download_abort(gi->job);
901                        ecore_file_remove(gi->file);
902                        gi->job = NULL;
903                     }
904                   gi->download = EINA_FALSE;
905                }
906              else if (gi->have)
907                {
908                   evas_object_hide(gi->img);
909                   //evas_object_hide(gi->txt);
910                   evas_object_image_preload(gi->img, 1);
911                   evas_object_image_file_set(gi->img, NULL, NULL);
912                   gi->have = EINA_FALSE;
913                   gi->want = EINA_FALSE;
914                }
915           }
916      }
917    eina_iterator_free(it);
918
919    xx = wd->pan_x / size;
920    if (xx < 0) xx = 0;
921
922    yy = wd->pan_y / size;
923    if (yy < 0) yy = 0;
924
925    ww = ow / size + 1;
926    if (xx + ww >= g->gw) ww = g->gw - xx - 1;
927
928    hh = oh / size + 1;
929    if (yy + hh >= g->gh) hh = g->gh - yy - 1;
930
931    for (y = yy; y <= yy + hh; y++)
932      {
933         for (x = xx; x <= xx + ww; x++)
934           {
935              gi = eina_matrixsparse_data_idx_get(g->grid, y, x);
936
937              if ((!gi) && (g != eina_list_data_get(wd->grids)))
938                continue;
939
940              if (!gi)
941                {
942                   gi = calloc(1, sizeof(Grid_Item));
943                   gi->src.x = x * g->tsize;
944                   gi->src.y = y * g->tsize;
945                   gi->src.w = g->tsize;
946                   gi->src.h = g->tsize;
947
948                   gi->out.x = gi->src.x;
949                   gi->out.y = gi->src.y;
950                   gi->out.w = gi->src.w;
951                   gi->out.h = gi->src.h;
952
953                   gi->wd = wd;
954                   
955                   gi->img = evas_object_image_add(evas_object_evas_get(obj));
956                   evas_object_image_scale_hint_set
957                     (gi->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
958                   evas_object_image_filled_set(gi->img, 1);
959                   
960                   evas_object_smart_member_add(gi->img, wd->pan_smart);
961                   elm_widget_sub_object_add(obj, gi->img);
962                   evas_object_pass_events_set(gi->img, EINA_TRUE);
963                   evas_object_stack_below(gi->img, wd->sep_maps_markers);
964                   
965                   /*gi->txt = evas_object_text_add(evas_object_evas_get(obj));
966                    evas_object_text_font_set(gi->txt, "Vera", 12);
967                    evas_object_color_set(gi->txt, 100, 100, 100, 255);
968                    evas_object_smart_member_add(gi->txt,
969                    wd->pan_smart);
970                    elm_widget_sub_object_add(obj, gi->txt);
971                    evas_object_pass_events_set(gi->txt, EINA_TRUE);
972                    */
973                   eina_matrixsparse_data_idx_set(g->grid, y, x, gi);
974                }
975              
976              if (!gi->have && !gi->download)
977                {
978                   char buf[PATH_MAX], buf2[PATH_MAX];
979                   char *source;
980                   
981                   gi->want = EINA_TRUE;
982                   
983                   snprintf(buf, sizeof(buf), DEST_DIR_PATH, wd->id, g->zoom, x);
984                   if (!ecore_file_exists(buf))
985                     ecore_file_mkpath(buf);
986                   
987                   snprintf(buf2, sizeof(buf2), DEST_FILE_PATH, buf, y);
988                   
989                   source = map_sources_tab[wd->source].url_cb(obj, x, y, g->zoom);
990                   if(strlen(source)==0) continue;
991                   
992                   eina_stringshare_replace(&gi->file, buf2);
993
994                   if (ecore_file_exists(buf2) || g == eina_list_data_get(wd->grids))
995                     {
996                        gi->download = EINA_TRUE;
997                        wd->preload_num++;
998                        if (wd->preload_num == 1)
999                          {
1000                             edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1001                                                     "elm,state,busy,start", "elm");
1002                             evas_object_smart_callback_call(obj,
1003                                                             SIG_LOAD_DETAIL,
1004                                                             NULL);
1005                          }
1006                        
1007                        if (ecore_file_exists(buf2))
1008                          _tile_update(gi);
1009                        else
1010                          {
1011                             DBG("DOWNLOAD %s \t in %s", source, buf2);
1012                             ecore_file_download(source, buf2, _tile_downloaded, NULL, gi, &(gi->job));
1013                             if (!gi->job)
1014                               DBG("Can't start to download %s", buf);
1015                          }
1016                     }
1017                   if (source) free(source);
1018                }
1019              else if (gi->have)
1020                evas_object_show(gi->img);
1021           }
1022      }
1023 }
1024
1025 static void
1026 grid_clearall(Evas_Object *obj)
1027 {
1028    Widget_Data *wd = elm_widget_data_get(obj);
1029    Grid *g;
1030
1031    if (!wd) return;
1032    EINA_LIST_FREE(wd->grids, g)
1033      {
1034         grid_clear(obj, g);
1035         free(g);
1036      }
1037 }
1038
1039 static void
1040 _smooth_update(Evas_Object *obj)
1041 {
1042    Widget_Data *wd = elm_widget_data_get(obj);
1043    Eina_List *l;
1044    Grid *g;
1045
1046    if (!wd) return;
1047    EINA_LIST_FOREACH(wd->grids, l, g)
1048      {
1049         Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
1050         Eina_Matrixsparse_Cell *cell;
1051         
1052         EINA_ITERATOR_FOREACH(it, cell)
1053           {
1054              Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
1055              evas_object_image_smooth_scale_set(gi->img, (wd->nosmooth == 0));
1056           }
1057         eina_iterator_free(it);
1058      }
1059 }
1060
1061 static void
1062 _grid_raise(Grid *g)
1063 {
1064    Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
1065    Eina_Matrixsparse_Cell *cell;
1066
1067    g->wd->size.w = g->w;
1068    g->wd->size.h = g->h;
1069
1070    EINA_ITERATOR_FOREACH(it, cell)
1071      {
1072         Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
1073         evas_object_raise(gi->img);
1074         //evas_object_raise(gi->txt);
1075      }
1076    eina_iterator_free(it);
1077 }
1078
1079 static Eina_Bool
1080 _scr_timeout(void *data)
1081 {
1082    Widget_Data *wd = elm_widget_data_get(data);
1083    if (!wd) return ECORE_CALLBACK_CANCEL;
1084    wd->nosmooth--;
1085    if (wd->nosmooth == 0) _smooth_update(data);
1086    wd->scr_timer = NULL;
1087    return ECORE_CALLBACK_CANCEL;
1088 }
1089
1090 static void
1091 _scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1092 {
1093    Widget_Data *wd = elm_widget_data_get(data);
1094    if (!wd) return;
1095    if (!wd->scr_timer)
1096      {
1097         wd->nosmooth++;
1098         if (wd->nosmooth == 1) _smooth_update(data);
1099      }
1100    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
1101    wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
1102 }
1103
1104 static Eina_Bool
1105 zoom_do(Evas_Object *obj, double t)
1106 {
1107    Widget_Data *wd = elm_widget_data_get(obj);
1108    Evas_Coord xx, yy, ow, oh;
1109
1110    if (!wd) return 0;
1111    if (t > 1.0) t = 1.0;
1112
1113    wd->size.w = (wd->size.ow * (1.0 - t)) + (wd->size.nw * t);
1114    wd->size.h = (wd->size.oh * (1.0 - t)) + (wd->size.nh * t);
1115
1116    elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
1117
1118    if (wd->center_on.enabled)
1119      {
1120         elm_map_utils_convert_geo_into_coord(obj, wd->center_on.lon, wd->center_on.lat, wd->size.w, &xx, &yy);
1121         xx -= ow / 2;
1122         yy -= oh / 2;
1123      }
1124    else
1125      {
1126         xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
1127         yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
1128      }
1129
1130    if (xx < 0) xx = 0;
1131    else if (xx > (wd->size.w - ow)) xx = wd->size.w - ow;
1132    if (yy < 0) yy = 0;
1133    else if (yy > (wd->size.h - oh)) yy = wd->size.h - oh;
1134
1135    wd->show.show = EINA_TRUE;
1136    wd->show.x = xx;
1137    wd->show.y = yy;
1138    wd->show.w = ow;
1139    wd->show.h = oh;
1140
1141    if (wd->calc_job) ecore_job_del(wd->calc_job);
1142    wd->calc_job = ecore_job_add(_calc_job, wd);
1143    if (t >= 1.0)
1144      {
1145         return ECORE_CALLBACK_CANCEL;
1146      }
1147    return ECORE_CALLBACK_RENEW;
1148 }
1149
1150 static Eina_Bool
1151 _zoom_anim(void *data)
1152 {
1153    Evas_Object *obj = data;
1154    Widget_Data *wd = elm_widget_data_get(obj);
1155    double t;
1156    int go;
1157
1158    if (!wd) return ECORE_CALLBACK_CANCEL;
1159    t = ecore_loop_time_get();
1160    if (t >= wd->t_end)
1161      t = 1.0;
1162    else if (wd->t_end > wd->t_start)
1163      t = (t - wd->t_start) / (wd->t_end - wd->t_start);
1164    else
1165      t = 1.0;
1166    t = 1.0 - t;
1167    t = 1.0 - (t * t);
1168    go = zoom_do(obj, t);
1169    if (!go)
1170      {
1171         wd->nosmooth--;
1172         if (wd->nosmooth == 0) _smooth_update(data);
1173         wd->zoom_animator = NULL;
1174         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
1175      }
1176    return go;
1177 }
1178
1179 static Eina_Bool
1180 _long_press(void *data)
1181 {
1182    Widget_Data *wd = elm_widget_data_get(data);
1183    if (!wd) return ECORE_CALLBACK_CANCEL;
1184    wd->long_timer = NULL;
1185    wd->longpressed = EINA_TRUE;
1186    evas_object_smart_callback_call(data, SIG_LONGPRESSED, NULL);
1187    return ECORE_CALLBACK_CANCEL;
1188 }
1189
1190 static void
1191 _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1192 {
1193    Widget_Data *wd = elm_widget_data_get(data);
1194    Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down*)event_info;
1195    struct event_t *ev0;
1196    
1197    ev0 = get_event_object(0);
1198    if(!ev0){
1199       ev0 = create_event_object(obj, 0);
1200       if(ev0){
1201          ev0->hold_timer = NULL;
1202          ev0->prev.x = ev->output.x;
1203          ev0->prev.y = ev->output.y;
1204       }else return;
1205    }else return;
1206
1207    if (!wd) return;
1208    if (ev->button != 1) return;
1209    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
1210    else wd->on_hold = EINA_FALSE;
1211    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
1212      evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, ev);
1213    else
1214      evas_object_smart_callback_call(data, SIG_PRESS, ev);
1215    wd->longpressed = EINA_FALSE;
1216    if (wd->long_timer) ecore_timer_del(wd->long_timer);
1217    wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data);
1218 }
1219
1220 static void
1221 _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1222 {
1223    Widget_Data *wd = elm_widget_data_get(data);
1224    Evas_Event_Mouse_Move *move = (Evas_Event_Mouse_Move *)event_info;
1225    struct event_t *ev0;
1226    if(wd->pinch_zoom) return;
1227    ev0 = get_event_object(0);
1228    if(ev0 == NULL) return;
1229         
1230    ev0->prev.x = move->cur.output.x;
1231    ev0->prev.y = move->cur.output.y;
1232 }
1233
1234 static void
1235 _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1236 {
1237    Widget_Data *wd = elm_widget_data_get(data);
1238    Evas_Event_Mouse_Up *ev = event_info;
1239
1240    int mdevice;
1241    struct event_t *ev0;
1242    struct event_t *ev1 = NULL;
1243    
1244    ev0 = get_event_object(0);
1245    if(ev0 != NULL) {
1246       mdevice = get_multi_device();
1247       if(mdevice == 0) {
1248          if(ev0->hold_timer == NULL){
1249          }else{
1250             ecore_timer_del(ev0->hold_timer);
1251             ev0->hold_timer = NULL;
1252          }
1253          elm_smart_scroller_hold_set(wd->scr, 0);
1254          elm_smart_scroller_freeze_set(wd->scr, 0);
1255          elm_smart_scroller_freeze_momentum_animator_set(wd->scr, 0);
1256          elm_smart_scroller_freeze_bounce_animator_set(wd->scr, 0);
1257          wd->pinch_zoom = EINA_FALSE;
1258       }else{
1259          ev1 = get_event_object(mdevice);
1260          if(ev1 != NULL){
1261             ev1->hold_timer = ecore_timer_add(0.35f, hold_timer_cb, ev1);
1262          }
1263       }
1264       destroy_event_object(ev0);
1265    }else{
1266       DBG("Cannot get event0");
1267    }
1268    if (!wd) return;
1269    if (ev->button != 1) return;
1270    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
1271    else wd->on_hold = EINA_FALSE;
1272    if (wd->long_timer){
1273       ecore_timer_del(wd->long_timer);
1274       wd->long_timer = NULL;
1275    }
1276    if (!wd->on_hold)
1277    evas_object_smart_callback_call(data, SIG_CLICKED, ev);
1278    wd->on_hold = EINA_FALSE;
1279 }
1280
1281 static void
1282 _mouse_multi_down(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1283 {
1284    Widget_Data *wd = elm_widget_data_get(data);
1285    struct event_t *ev;
1286    Evas_Event_Multi_Down *down = event_info;
1287
1288    elm_smart_scroller_hold_set(wd->scr, 1);
1289    elm_smart_scroller_freeze_set(wd->scr, 1);
1290    elm_smart_scroller_freeze_momentum_animator_set(wd->scr, 1);
1291    elm_smart_scroller_freeze_bounce_animator_set(wd->scr, 1);
1292
1293    ev = get_event_object(down->device);
1294    if(ev) goto done;
1295
1296    ev = create_event_object(obj, down->device);
1297    if(!ev){
1298       DBG("Failed : create_event_object");
1299       goto done;
1300    }
1301
1302    wd->pinch_zoom = EINA_FALSE;
1303
1304    ev->hold_timer = NULL;
1305    ev->prev.x = down->output.x;
1306    ev->prev.y = down->output.y;
1307
1308 done:
1309    return;
1310 error:
1311    elm_smart_scroller_hold_set(wd->scr, 0);
1312    elm_smart_scroller_freeze_set(wd->scr, 0);
1313    elm_smart_scroller_freeze_momentum_animator_set(wd->scr, 0);
1314    elm_smart_scroller_freeze_bounce_animator_set(wd->scr, 0);
1315
1316 }
1317
1318 static void
1319 _mouse_multi_move(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1320 {
1321    Widget_Data *wd = elm_widget_data_get(data);
1322    Evas_Event_Multi_Move *move = (Evas_Event_Multi_Move *)event_info;
1323    int dis_new;
1324    struct event_t *ev0;
1325    struct event_t *ev;
1326
1327    if(wd->pinch_zoom) return;
1328    ev = get_event_object(move->device);
1329    if(ev == NULL) {
1330       DBG("Cannot get multi device");
1331       return;
1332    }
1333
1334    ev->prev.x = move->cur.output.x;
1335    ev->prev.y = move->cur.output.y;
1336
1337    ev0 = get_event_object(0);
1338    if(ev0 == NULL) {
1339       DBG("Cannot get device0");
1340       return;
1341    }
1342
1343    dis_new = get_distance(ev0->prev.x, ev0->prev.y, ev->prev.x, ev->prev.y);
1344    int zoom = wd->zoom;
1345    
1346    if(dis_old != 0) {
1347       if(dis_old - dis_new > 0 && ev->pinch_dis > TOUCH_HOLD_RANGE){
1348          wd->pinch_zoom = EINA_TRUE;
1349          --zoom;
1350          elm_map_zoom_set(data, zoom);
1351          ev->pinch_dis = 0;
1352       }else if(dis_old - dis_new < 0 && ev->pinch_dis < -TOUCH_HOLD_RANGE){
1353          wd->pinch_zoom = EINA_TRUE;
1354          ++zoom;
1355          elm_map_zoom_set(data, zoom);
1356          ev->pinch_dis = 0;
1357       }
1358
1359       ev->pinch_dis += (dis_old - dis_new);
1360    }
1361    dis_old = dis_new;
1362 }
1363
1364 static void
1365 _mouse_multi_up(void *data, Evas *evas, Evas_Object *obj, void *event_info)
1366 {
1367    Evas_Event_Multi_Up *up = (Evas_Event_Multi_Up *)event_info;
1368    struct event_t *ev0;
1369    struct event_t *ev;
1370
1371    ev = get_event_object(up->device);
1372    if(ev == NULL){
1373       DBG("Cannot get multi device");
1374       return;
1375    }
1376    dis_old = 0;
1377    
1378    ev0 = get_event_object(0);
1379    if(ev0){
1380       ev0->hold_timer = ecore_timer_add(0.35f, hold_timer_cb, ev0);
1381    }else{
1382       if(ev->hold_timer == NULL) {
1383       } else {
1384          ecore_timer_del(ev->hold_timer);
1385          ev->hold_timer = NULL;
1386       }   
1387    }
1388    destroy_event_object(ev);
1389 }
1390
1391 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL;
1392
1393 static void
1394 _del_hook(Evas_Object *obj)
1395 {
1396    Elm_Map_Group_Class *group_clas;
1397    Elm_Map_Marker_Class *marker_clas;
1398    Widget_Data *wd = elm_widget_data_get(obj);
1399
1400    if (!wd) return;
1401
1402    EINA_LIST_FREE(wd->groups_clas, group_clas)
1403      {
1404         if (group_clas->style)
1405           eina_stringshare_del(group_clas->style);
1406         free(group_clas);
1407      }
1408
1409    EINA_LIST_FREE(wd->markers_clas, marker_clas)
1410      {
1411         if (marker_clas->style)
1412           eina_stringshare_del(marker_clas->style);
1413         free(marker_clas);
1414      }
1415
1416    if (wd->calc_job) ecore_job_del(wd->calc_job);
1417    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
1418    if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
1419    if (wd->long_timer) ecore_timer_del(wd->long_timer);
1420
1421    if ((wd->api) && (wd->api->obj_unhook)) wd->api->obj_unhook(obj);
1422    free(wd);
1423 }
1424
1425 static void
1426 _del_pre_hook(Evas_Object *obj)
1427 {
1428    Marker_Group *group;
1429    Elm_Map_Marker *marker;
1430    int i;
1431    Eina_Bool free_marker = EINA_TRUE;
1432    Eina_List *l;
1433    Widget_Data *wd = elm_widget_data_get(obj);
1434    grid_clearall(obj);
1435
1436    if (!wd) return;
1437    for (i = 0; i < ZOOM_MAX + 1; i++)
1438      {
1439         if (!wd->markers[i]) continue;
1440         Eina_Iterator *it = eina_matrixsparse_iterator_new(wd->markers[i]);
1441         Eina_Matrixsparse_Cell *cell;
1442         
1443         EINA_ITERATOR_FOREACH(it, cell)
1444           {
1445              l =  eina_matrixsparse_cell_data_get(cell);
1446              EINA_LIST_FREE(l, group)
1447                {
1448                   EINA_LIST_FREE(group->markers, marker)
1449                     {
1450                        evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1451                                                            _bubble_sc_hits_changed_cb, group);
1452                        if (free_marker) free(marker);
1453                     }
1454                   free(group);
1455                }
1456              free_marker = EINA_FALSE;
1457           }
1458         eina_iterator_free(it);
1459         eina_matrixsparse_free(wd->markers[i]);
1460      }
1461
1462    evas_object_del(wd->sep_maps_markers);
1463    evas_object_del(wd->pan_smart);
1464    wd->pan_smart = NULL;
1465 }
1466
1467 static void
1468 _theme_hook(Evas_Object *obj)
1469 {
1470    Widget_Data *wd = elm_widget_data_get(obj);
1471    if (!wd) return;
1472    elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", elm_widget_style_get(obj));
1473 //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
1474    _sizing_eval(obj);
1475 }
1476
1477 static void
1478 _sizing_eval(Evas_Object *obj)
1479 {
1480    Widget_Data *wd = elm_widget_data_get(obj);
1481    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
1482    if (!wd) return;
1483    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
1484    evas_object_size_hint_min_set(obj, minw, minh);
1485    evas_object_size_hint_max_set(obj, maxw, maxh);
1486 }
1487
1488 static void
1489 _calc_job(void *data)
1490 {
1491    Widget_Data *wd = data;
1492    Evas_Coord minw, minh;
1493
1494    minw = wd->size.w;
1495    minh = wd->size.h;
1496    if (wd->resized)
1497      {
1498         wd->resized = 0;
1499         if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
1500           {
1501              double tz = wd->zoom;
1502              wd->zoom = 0.0;
1503              elm_map_zoom_set(wd->obj, tz);
1504           }
1505      }
1506    if ((minw != wd->minw) || (minh != wd->minh))
1507      {
1508         wd->minw = minw;
1509         wd->minh = minh;
1510         evas_object_smart_callback_call(wd->pan_smart, SIG_CHANGED, NULL);
1511         _sizing_eval(wd->obj);
1512      }
1513    wd->calc_job = NULL;
1514    evas_object_smart_changed(wd->pan_smart);
1515 }
1516
1517 static void
1518 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1519 {
1520    Pan *sd = evas_object_smart_data_get(obj);
1521    if (!sd) return;
1522    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
1523    sd->wd->pan_x = x;
1524    sd->wd->pan_y = y;
1525    evas_object_smart_changed(obj);
1526 }
1527
1528 static void
1529 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1530 {
1531    Pan *sd = evas_object_smart_data_get(obj);
1532    if (!sd) return;
1533    if (x) *x = sd->wd->pan_x;
1534    if (y) *y = sd->wd->pan_y;
1535 }
1536
1537 static void
1538 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1539 {
1540    Pan *sd = evas_object_smart_data_get(obj);
1541    Evas_Coord ow, oh;
1542    if (!sd) return;
1543    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1544    ow = sd->wd->minw - ow;
1545    if (ow < 0) ow = 0;
1546    oh = sd->wd->minh - oh;
1547    if (oh < 0) oh = 0;
1548    if (x) *x = ow;
1549    if (y) *y = oh;
1550 }
1551
1552 static void
1553 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1554 {
1555    Pan *sd = evas_object_smart_data_get(obj);
1556    if (!sd) return;
1557    if (w) *w = sd->wd->minw;
1558    if (h) *h = sd->wd->minh;
1559 }
1560
1561 static void
1562 _pan_add(Evas_Object *obj)
1563 {
1564    Pan *sd;
1565    Evas_Object_Smart_Clipped_Data *cd;
1566    _pan_sc.add(obj);
1567    cd = evas_object_smart_data_get(obj);
1568    if (!cd) return;
1569    sd = calloc(1, sizeof(Pan));
1570    if (!sd) return;
1571    sd->__clipped_data = *cd;
1572    free(cd);
1573    evas_object_smart_data_set(obj, sd);
1574 }
1575
1576 static void
1577 _pan_del(Evas_Object *obj)
1578 {
1579    Pan *sd = evas_object_smart_data_get(obj);
1580    if (!sd) return;
1581    _pan_sc.del(obj);
1582 }
1583
1584 static void
1585 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
1586 {
1587    Pan *sd = evas_object_smart_data_get(obj);
1588    Evas_Coord ow, oh;
1589    if (!sd) return;
1590    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1591    if ((ow == w) && (oh == h)) return;
1592    sd->wd->resized = 1;
1593    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1594    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1595 }
1596
1597 static void
1598 _pan_calculate(Evas_Object *obj)
1599 {
1600    Pan *sd = evas_object_smart_data_get(obj);
1601    Evas_Coord ox, oy, ow, oh;
1602    Eina_List *l;
1603    Grid *g;
1604    if (!sd) return;
1605    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
1606    rect_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
1607    EINA_LIST_FOREACH(sd->wd->grids, l, g)
1608      {
1609         grid_load(sd->wd->obj, g);
1610         grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
1611         marker_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
1612      }
1613 }
1614
1615 static void
1616 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
1617 {
1618    Pan *sd = evas_object_smart_data_get(obj);
1619    if (!sd) return;
1620    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1621    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1622 }
1623
1624 static void
1625 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1626 {
1627    Widget_Data *wd = elm_widget_data_get(obj);
1628    if (!wd) return;
1629    elm_smart_scroller_hold_set(wd->scr, 1);
1630 }
1631
1632 static void
1633 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1634 {
1635    Widget_Data *wd = elm_widget_data_get(obj);
1636    if (!wd) return;
1637    elm_smart_scroller_hold_set(wd->scr, 0);
1638 }
1639
1640 static void
1641 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1642 {
1643    Widget_Data *wd = elm_widget_data_get(obj);
1644    if (!wd) return;
1645    elm_smart_scroller_freeze_set(wd->scr, 1);
1646 }
1647
1648 static void
1649 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1650 {
1651    Widget_Data *wd = elm_widget_data_get(obj);
1652    if (!wd) return;
1653    elm_smart_scroller_freeze_set(wd->scr, 0);
1654 }
1655
1656 static void
1657 _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1658 {
1659    evas_object_smart_callback_call(data, "scroll,anim,start", NULL);
1660 }
1661
1662 static void
1663 _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1664 {
1665    evas_object_smart_callback_call(data, "scroll,anim,stop", NULL);
1666 }
1667
1668 static void
1669 _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1670 {
1671    Widget_Data *wd = elm_widget_data_get(data);
1672    wd->center_on.enabled = EINA_FALSE;
1673    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
1674 }
1675
1676 static void
1677 _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1678 {
1679    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
1680 }
1681
1682 static void
1683 _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1684 {
1685    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
1686 }
1687
1688
1689 static void
1690 _group_object_create(Marker_Group *group)
1691 {
1692    const char *style = "radio";
1693    Evas_Object *icon = NULL;
1694
1695    if (group->obj) return;
1696    if (!group->clas->priv.objs_notused || eina_list_count(group->markers) == 1)
1697      {
1698         //set icon and style
1699         if (eina_list_count(group->markers) == 1)
1700           {
1701              Elm_Map_Marker *m = eina_list_data_get(group->markers);
1702              if (m->clas->style)
1703                style = m->clas->style;
1704              
1705              if (m->clas->func.icon_get)
1706                icon = m->clas->func.icon_get(group->wd->obj, m, m->data);
1707              
1708              group->delete_object = EINA_TRUE;
1709           }
1710         else
1711           {
1712              if (group->clas->style)
1713                style = group->clas->style;
1714              
1715              if (group->clas->func.icon_get)
1716                icon = group->clas->func.icon_get(group->wd->obj, group->clas->data);
1717              
1718              group->delete_object = EINA_FALSE;
1719           }
1720         
1721         group->obj = elm_layout_add(group->wd->obj);
1722         elm_layout_theme_set(group->obj, "map/marker", style, elm_widget_style_get(group->wd->obj));
1723
1724         if (icon) elm_layout_content_set(group->obj, "elm.icon", icon);
1725         
1726         evas_object_smart_member_add(group->obj, group->wd->pan_smart);
1727         elm_widget_sub_object_add(group->wd->obj, group->obj);
1728         evas_object_stack_above(group->obj, group->wd->sep_maps_markers);
1729
1730         if (!group->delete_object)
1731           group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
1732      }
1733    else
1734      {
1735         group->delete_object = EINA_FALSE;
1736         
1737         group->obj = eina_list_data_get(group->clas->priv.objs_notused);
1738         group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
1739         group->clas->priv.objs_notused = eina_list_remove(group->clas->priv.objs_notused, group->obj);
1740         evas_object_show(group->obj);
1741      }
1742
1743    edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb, group);
1744    edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb, group);
1745
1746    group->update_nbelems = EINA_TRUE;
1747    group->update_resize = EINA_TRUE;
1748    group->update_raise = EINA_TRUE;
1749
1750    if (group->open) _group_bubble_create(group);
1751 }
1752
1753 static void
1754 _group_object_free(Marker_Group *group)
1755 {
1756    if (!group->obj) return;
1757    if (!group->delete_object)
1758      {
1759         group->clas->priv.objs_notused = eina_list_append(group->clas->priv.objs_notused, group->obj);
1760         group->clas->priv.objs_used = eina_list_remove(group->clas->priv.objs_used, group->obj);
1761         evas_object_hide(group->obj);
1762
1763         edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb);
1764         edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb);
1765      }
1766    else
1767      evas_object_del(group->obj);
1768
1769    group->obj = NULL;
1770    _group_bubble_free(group);
1771 }
1772
1773 static void
1774 _group_bubble_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1775 {
1776    Marker_Group *group = data;
1777
1778    if (!evas_object_above_get(group->rect)) return;
1779    evas_object_raise(group->bubble);
1780    evas_object_raise(group->sc);
1781    evas_object_raise(group->rect);
1782 }
1783
1784 static void
1785 _group_bubble_create(Marker_Group *group)
1786 {
1787    if (group->bubble) return;
1788
1789    group->wd->opened_bubbles = eina_list_append(group->wd->opened_bubbles, group);
1790    group->bubble = edje_object_add(evas_object_evas_get(group->obj));
1791    _elm_theme_object_set(group->wd->obj, group->bubble, "map", "marker_bubble",
1792                          elm_widget_style_get(group->wd->obj));
1793    evas_object_smart_member_add(group->bubble,
1794                                 group->wd->obj);
1795    elm_widget_sub_object_add(group->wd->obj, group->bubble);
1796    
1797    _group_bubble_content_free(group);
1798    if (!_group_bubble_content_update(group))
1799      {
1800         //no content, we can delete the bubble
1801         _group_bubble_free(group);
1802         return;
1803      }
1804    
1805    group->rect = evas_object_rectangle_add(evas_object_evas_get(group->obj));
1806    evas_object_color_set(group->rect, 0, 0, 0, 0);
1807    evas_object_repeat_events_set(group->rect, EINA_TRUE);
1808    evas_object_smart_member_add(group->rect, group->wd->obj);
1809    elm_widget_sub_object_add(group->wd->obj, group->rect);
1810    
1811    evas_object_event_callback_add(group->rect, EVAS_CALLBACK_MOUSE_UP, _group_bubble_mouse_up_cb, group);
1812    
1813    _group_bubble_place(group);
1814 }
1815
1816 static void _bubble_sc_hits_changed_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1817 {
1818    _group_bubble_place(data);
1819 }
1820
1821 static int
1822 _group_bubble_content_update(Marker_Group *group)
1823 {
1824    Eina_List *l;
1825    Elm_Map_Marker *marker;
1826    int i = 0;
1827
1828    if (!group->bubble) return 1;
1829
1830    if (!group->sc)
1831      {
1832         group->sc = elm_scroller_add(group->bubble);
1833         elm_scroller_content_min_limit(group->sc, EINA_FALSE, EINA_TRUE);
1834         elm_scroller_policy_set(group->sc, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
1835         elm_scroller_bounce_set(group->sc, EINA_TRUE, EINA_FALSE);
1836         edje_object_part_swallow(group->bubble, "elm.swallow.content", group->sc);
1837         evas_object_show(group->sc);
1838         evas_object_smart_member_add(group->sc,
1839                                      group->wd->obj);
1840         elm_widget_sub_object_add(group->wd->obj, group->sc);
1841         
1842         group->bx = elm_box_add(group->bubble);
1843         evas_object_size_hint_align_set(group->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
1844         evas_object_size_hint_weight_set(group->bx, 0.5, 0.5);
1845         elm_box_horizontal_set(group->bx, EINA_TRUE);
1846         evas_object_show(group->bx);
1847         
1848         elm_scroller_content_set(group->sc, group->bx);
1849         
1850         evas_object_event_callback_add(group->sc, EVAS_CALLBACK_RESIZE,
1851                                        _bubble_sc_hits_changed_cb, group);
1852      }
1853    
1854    EINA_LIST_FOREACH(group->markers, l, marker)
1855      {
1856         if (i >= group->wd->markers_max_num) break;
1857         if (!marker->content && marker->clas->func.get)
1858           marker->content = marker->clas->func.get(group->wd->obj, marker, marker->data);
1859         else if (marker->content)
1860           elm_box_unpack(group->bx, marker->content);
1861         if (marker->content)
1862           {
1863              elm_box_pack_end(group->bx, marker->content);
1864              i++;
1865           }
1866      }
1867    return i;
1868 }
1869
1870 static void
1871 _group_bubble_content_free(Marker_Group *group)
1872 {
1873    Eina_List *l;
1874    Elm_Map_Marker *marker;
1875
1876    if (!group->sc) return;
1877    EINA_LIST_FOREACH(group->markers, l, marker)
1878      {
1879         if (marker->content && marker->clas->func.del)
1880           marker->clas->func.del(group->wd->obj, marker, marker->data, marker->content);
1881         else if (marker->content)
1882           evas_object_del(marker->content);
1883         marker->content = NULL;
1884      }
1885    evas_object_del(group->sc);
1886    group->sc = NULL;
1887 }
1888
1889 static void
1890 _group_bubble_free(Marker_Group *group)
1891 {
1892    if (!group->bubble) return;
1893    group->wd->opened_bubbles = eina_list_remove(group->wd->opened_bubbles, group);
1894    evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1895                                        _bubble_sc_hits_changed_cb, group);
1896    evas_object_del(group->bubble);
1897    evas_object_del(group->rect);
1898    group->bubble = NULL;
1899    _group_bubble_content_free(group);
1900 }
1901
1902 static void
1903 _group_bubble_place(Marker_Group *group)
1904 {
1905    Evas_Coord x, y, w;
1906    Evas_Coord xx, yy, ww, hh;
1907    const char *s;
1908
1909    if (!group->bubble || !group->obj) return;
1910
1911    evas_object_geometry_get(group->obj, &x, &y, &w, NULL);
1912    edje_object_size_min_calc(group->bubble, NULL, &hh);
1913
1914    s = edje_object_data_get(group->bubble, "size_w");
1915    ww = atoi(s);
1916    xx = x + w / 2 - ww / 2;
1917    yy = y-hh;
1918
1919    evas_object_move(group->bubble, xx, yy);
1920    evas_object_resize(group->bubble, ww, hh);
1921    evas_object_show(group->bubble);
1922
1923    evas_object_move(group->rect, xx, yy);
1924    evas_object_resize(group->rect, ww, hh);
1925    evas_object_show(group->rect);
1926 }
1927
1928 static void
1929 _group_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
1930 {
1931    Marker_Group *group = data;
1932    Elm_Map_Marker *marker = eina_list_data_get(group->markers);
1933    if (!marker) return;
1934    group->bringin = EINA_TRUE;
1935    elm_map_geo_region_bring_in(group->wd->obj, marker->longitude, marker->latitude);
1936 }
1937
1938 static void
1939 _group_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
1940 {
1941    Marker_Group *group = data;
1942
1943    if (group->bringin)
1944      {
1945         group->bringin = EINA_FALSE;
1946         return;
1947      }
1948
1949    if (group->bubble)
1950      {
1951         group->open = EINA_FALSE;
1952         _group_bubble_free(group);
1953         return;
1954      }
1955    group->open = EINA_TRUE;
1956    _group_bubble_create(group);
1957 }
1958
1959 static int idnum = 1;
1960
1961 /**
1962  * Add a new Map object
1963  *
1964  * @param parent The parent object
1965  * @return The new object or NULL if it cannot be created
1966  *
1967  * @ingroup Map
1968  */
1969 EAPI Evas_Object *
1970 elm_map_add(Evas_Object *parent)
1971 {
1972    Evas *e;
1973    Widget_Data *wd;
1974    Evas_Coord minw, minh;
1975    Evas_Object *obj;
1976    Eina_Bool ret = EINA_FALSE;
1977    int idx;
1978    static Evas_Smart *smart = NULL;
1979
1980    if (!ecore_file_download_protocol_available("http://"))
1981      {
1982         ERR("Ecore must be built with the support of HTTP for the widget map !");
1983         return NULL;
1984      }
1985
1986    wd = ELM_NEW(Widget_Data);
1987    wd->api = NULL;
1988    e = evas_object_evas_get(parent);
1989    obj = elm_widget_add(e);
1990    ELM_SET_WIDTYPE(widtype, "map");
1991    elm_widget_type_set(obj, "map");
1992    elm_widget_sub_object_add(parent, obj);
1993    elm_widget_data_set(obj, wd);
1994    elm_widget_del_hook_set(obj, _del_hook);
1995    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1996    elm_widget_theme_hook_set(obj, _theme_hook);
1997
1998    wd->scr = elm_smart_scroller_add(e);
1999    elm_smart_scroller_widget_set(wd->scr, obj);
2000    elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", "default");
2001    evas_object_smart_callback_add(wd->scr, "scroll", _scr, obj);
2002    evas_object_smart_callback_add(wd->scr, "drag", _scr, obj);
2003    elm_widget_resize_object_set(obj, wd->scr);
2004
2005    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
2006    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
2007    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
2008    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
2009    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
2010
2011    elm_smart_scroller_bounce_allow_set(wd->scr, EINA_TRUE, EINA_TRUE);
2012
2013    wd->obj = obj;
2014
2015    wd->markers_max_num = 30;
2016    wd->source = ELM_MAP_SOURCE_MAPNIK;
2017
2018    for(idx=ELM_MAP_SOURCE_MAPNIK; idx<=ELM_MAP_SOURCE_CUSTOM_6; idx++)
2019    if(map_sources_tab[idx].use_module == EINA_TRUE){
2020       if(!wd->api){
2021          wd->api = module(obj);
2022          if ((wd->api) && (wd->api->obj_hook)) ret = wd->api->obj_hook(obj);
2023          if (!ret) DBG("Failed : loading module [%s]", elm_map_source_name_get(idx));
2024       }
2025    }
2026
2027    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
2028    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
2029    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
2030    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
2031
2032    if (!smart)
2033      {
2034         static Evas_Smart_Class sc;
2035
2036         evas_object_smart_clipped_smart_set(&_pan_sc);
2037         sc = _pan_sc;
2038         sc.name = "elm_map_pan";
2039         sc.version = EVAS_SMART_CLASS_VERSION;
2040         sc.add = _pan_add;
2041         sc.del = _pan_del;
2042         sc.resize = _pan_resize;
2043         sc.move = _pan_move;
2044         sc.calculate = _pan_calculate;
2045         smart = evas_smart_class_new(&sc);
2046      }
2047    if (smart)
2048      {
2049         wd->pan_smart = evas_object_smart_add(e, smart);
2050         wd->pan = evas_object_smart_data_get(wd->pan_smart);
2051         wd->pan->wd = wd;
2052      }
2053
2054    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
2055          _pan_set, _pan_get,
2056          _pan_max_get, _pan_child_size_get);
2057
2058    wd->rect = evas_object_rectangle_add(e);
2059    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_RESIZE, _rect_resize_cb, obj);
2060    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_DOWN,
2061          _mouse_down, obj);
2062    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_UP,
2063          _mouse_up, obj);
2064    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_MOVE,
2065          _mouse_move, obj);
2066    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_DOWN, 
2067          _mouse_multi_down, obj);
2068    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_MOVE,
2069          _mouse_multi_move, obj);
2070    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_UP,
2071          _mouse_multi_up, obj);
2072
2073    evas_object_smart_member_add(wd->rect, wd->pan_smart);
2074    elm_widget_sub_object_add(obj, wd->rect);
2075    evas_object_show(wd->rect);
2076    evas_object_color_set(wd->rect, 0, 0, 0, 0);
2077
2078    wd->zoom = -1;
2079    wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
2080    wd->id = ((int)getpid() << 16) | idnum;
2081    idnum++;
2082
2083    wd->tsize = 256;
2084
2085    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
2086          &minw, &minh);
2087    evas_object_size_hint_min_set(obj, minw, minh);
2088
2089    wd->paused = EINA_TRUE;
2090    elm_map_zoom_set(obj, 0);
2091    wd->paused = EINA_FALSE;
2092
2093    _sizing_eval(obj);
2094
2095    wd->calc_job = ecore_job_add(_calc_job, wd);
2096
2097    wd->sep_maps_markers = evas_object_rectangle_add(evas_object_evas_get(obj));
2098    evas_object_smart_member_add(wd->sep_maps_markers, wd->pan_smart);
2099
2100    // TODO: convert Elementary to subclassing of Evas_Smart_Class
2101    // TODO: and save some bytes, making descriptions per-class and not instance!
2102    evas_object_smart_callbacks_descriptions_set(obj, _signals);
2103    return obj;
2104 }
2105
2106 /**
2107  * Set the zoom level of the map
2108  *
2109  * This sets the zoom level. 0 is the world map and 18 is the maximum zoom.
2110  *
2111  * @param obj The map object
2112  * @param zoom The zoom level to set
2113  *
2114  * @ingroup Map
2115  */
2116 EAPI void
2117 elm_map_zoom_set(Evas_Object *obj, int zoom)
2118 {
2119    ELM_CHECK_WIDTYPE(obj, widtype);
2120    Widget_Data *wd = elm_widget_data_get(obj);
2121    Eina_List *l;
2122    Grid *g, *g_zoom = NULL;
2123    Evas_Coord rx, ry, rw, rh;
2124    int z;
2125    int zoom_changed = 0, started = 0;
2126    
2127    if (!wd) return;
2128    if (zoom < 0 ) zoom = 0;
2129    if (zoom > map_sources_tab[wd->source].zoom_max)
2130      zoom = map_sources_tab[wd->source].zoom_max;
2131    if (zoom < map_sources_tab[wd->source].zoom_min)
2132      zoom = map_sources_tab[wd->source].zoom_min;
2133    if (zoom == wd->zoom) return;
2134    if (wd->zoom_animator) return;
2135
2136    wd->zoom = zoom;
2137    wd->size.ow = wd->size.w;
2138    wd->size.oh = wd->size.h;
2139    elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
2140    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
2141
2142    if (wd->mode == ELM_MAP_ZOOM_MODE_MANUAL)
2143      {
2144         wd->size.nw = pow(2.0, wd->zoom) * wd->tsize;
2145         wd->size.nh = pow(2.0, wd->zoom) * wd->tsize;
2146      }
2147    else if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FIT)
2148      {
2149         int p2w, p2h;
2150         int cumulw, cumulh;
2151
2152         cumulw = wd->tsize;
2153         p2w = 0;
2154         while (cumulw <= rw)
2155           {
2156              p2w++;
2157              cumulw *= 2;
2158           }
2159         p2w--;
2160
2161         cumulh = wd->tsize;
2162         p2h = 0;
2163         while (cumulh <= rh)
2164           {
2165              p2h++;
2166              cumulh *= 2;
2167           }
2168         p2h--;
2169         
2170         if (p2w < p2h)
2171           z = p2w;
2172         else
2173           z = p2h;
2174         
2175         wd->zoom = z;
2176         wd->size.nw = pow(2.0, wd->zoom) * wd->tsize;
2177         wd->size.nh = pow(2.0, wd->zoom) * wd->tsize;
2178      }
2179    else if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FILL)
2180      {
2181         int p2w, p2h;
2182         int cumulw, cumulh;
2183         
2184         cumulw = wd->tsize;
2185         p2w = 0;
2186         while (cumulw <= rw)
2187           {
2188              p2w++;
2189              cumulw *= 2;
2190           }
2191         p2w--;
2192
2193         cumulh = wd->tsize;
2194         p2h = 0;
2195         while (cumulh <= rh)
2196           {
2197              p2h++;
2198              cumulh *= 2;
2199           }
2200         p2h--;
2201
2202         if (p2w > p2h)
2203           z = p2w;
2204         else
2205           z = p2h;
2206         
2207         wd->zoom = z;
2208         wd->size.nw = pow(2.0, wd->zoom) * wd->tsize;
2209         wd->size.nh = pow(2.0, wd->zoom) * wd->tsize;
2210      }
2211
2212    EINA_LIST_FOREACH(wd->grids, l, g)
2213      {
2214         if (g->zoom == wd->zoom)
2215           {
2216              wd->grids = eina_list_remove(wd->grids, g);
2217              wd->grids = eina_list_prepend(wd->grids, g);
2218              _grid_raise(g);
2219              goto done;
2220           }
2221      }
2222    g = grid_create(obj);
2223    if (g)
2224      {
2225         if (eina_list_count(wd->grids) > 1)
2226           {
2227              g_zoom = eina_list_last(wd->grids)->data;
2228              wd->grids = eina_list_remove(wd->grids, g_zoom);
2229              grid_clear(obj, g_zoom);
2230              free(g_zoom);
2231           }
2232         wd->grids = eina_list_prepend(wd->grids, g);
2233      }
2234    else
2235      {
2236         EINA_LIST_FREE(wd->grids, g)
2237           {
2238              grid_clear(obj, g);
2239              free(g);
2240           }
2241      }
2242 done:
2243
2244    wd->t_start = ecore_loop_time_get();
2245    wd->t_end = wd->t_start + _elm_config->zoom_friction;
2246    if ((wd->size.w > 0) && (wd->size.h > 0))
2247      {
2248         wd->size.spos.x = (double)(rx + (rw / 2)) / (double)wd->size.ow;
2249         wd->size.spos.y = (double)(ry + (rh / 2)) / (double)wd->size.oh;
2250      }
2251    else
2252      {
2253         wd->size.spos.x = 0.5;
2254         wd->size.spos.y = 0.5;
2255      }
2256    if (rw > wd->size.ow) wd->size.spos.x = 0.5;
2257    if (rh > wd->size.oh) wd->size.spos.y = 0.5;
2258    if (wd->size.spos.x > 1.0) wd->size.spos.x = 1.0;
2259    if (wd->size.spos.y > 1.0) wd->size.spos.y = 1.0;
2260    if (wd->paused)
2261      {
2262         zoom_do(obj, 1.0);
2263      }
2264    else
2265      {
2266         if (!wd->zoom_animator)
2267           {
2268              wd->zoom_animator = ecore_animator_add(_zoom_anim, obj);
2269              wd->nosmooth++;
2270              if (wd->nosmooth == 1) _smooth_update(obj);
2271              started = 1;
2272           }
2273      }
2274    if (wd->zoom_animator)
2275      {
2276         if (!_zoom_anim(obj))
2277           {
2278              ecore_animator_del(wd->zoom_animator);
2279              wd->zoom_animator = NULL;
2280           }
2281      }
2282    if (wd->calc_job) ecore_job_del(wd->calc_job);
2283    wd->calc_job = ecore_job_add(_calc_job, wd);
2284    if (!wd->paused)
2285      {
2286         if (started)
2287           evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL);
2288         if (!wd->zoom_animator)
2289           evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
2290      }
2291
2292    if (zoom_changed)
2293      evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL);
2294 }
2295
2296 /**
2297  * Get the zoom level of the photo
2298  *
2299  * This returns the current zoom level of the map object. Note that if
2300  * you set the fill mode to other than ELM_MAP_ZOOM_MODE_MANUAL
2301  * (which is the default), the zoom level may be changed at any time by the
2302  * map object itself to account for map size and map viewpoer size
2303  *
2304  * @param obj The map object
2305  * @return The current zoom level
2306  *
2307  * @ingroup Map
2308  */
2309 EAPI double
2310 elm_map_zoom_get(const Evas_Object *obj)
2311 {
2312    ELM_CHECK_WIDTYPE(obj, widtype) 1.0;
2313    Widget_Data *wd = elm_widget_data_get(obj);
2314    if (!wd) return 1.0;
2315    return wd->zoom;
2316 }
2317
2318 /**
2319  * Set the zoom mode
2320  *
2321  * This sets the zoom mode to manual or one of several automatic levels.
2322  * Manual (ELM_MAP_ZOOM_MODE_MANUAL) means that zoom is set manually by
2323  * elm_map_zoom_set() and will stay at that level until changed by code
2324  * or until zoom mode is changed. This is the default mode.
2325  * The Automatic modes will allow the map object to automatically
2326  * adjust zoom mode based on properties. ELM_MAP_ZOOM_MODE_AUTO_FIT) will
2327  * adjust zoom so the photo fits inside the scroll frame with no pixels
2328  * outside this area. ELM_MAP_ZOOM_MODE_AUTO_FILL will be similar but
2329  * ensure no pixels within the frame are left unfilled. Do not forget that the valid sizes are 2^zoom, consequently the map may be smaller than the scroller view.
2330  *
2331  * @param obj The map object
2332  * @param mode The desired mode
2333  *
2334  * @ingroup Map
2335  */
2336 EAPI void
2337 elm_map_zoom_mode_set(Evas_Object *obj, Elm_Map_Zoom_Mode mode)
2338 {
2339    ELM_CHECK_WIDTYPE(obj, widtype);
2340    Widget_Data *wd = elm_widget_data_get(obj);
2341    if (!wd) return;
2342    if (wd->mode == mode) return;
2343    wd->mode = mode;
2344      {
2345         double tz = wd->zoom;
2346         wd->zoom = 0.0;
2347         elm_map_zoom_set(wd->obj, tz);
2348      }
2349 }
2350
2351 /**
2352  * Get the zoom mode
2353  *
2354  * This gets the current zoom mode of the map object
2355  *
2356  * @param obj The map object
2357  * @return The current zoom mode
2358  *
2359  * @ingroup Map
2360  */
2361 EAPI Elm_Map_Zoom_Mode
2362 elm_map_zoom_mode_get(const Evas_Object *obj)
2363 {
2364    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_ZOOM_MODE_MANUAL;
2365    Widget_Data *wd = elm_widget_data_get(obj);
2366    if (!wd) return ELM_MAP_ZOOM_MODE_MANUAL;
2367    return wd->mode;
2368 }
2369
2370 /**
2371  * Centers the map at @p lon @p lat using an animation to scroll.
2372  *
2373  * @param obj The map object
2374  * @param lon Longitude to center at
2375  * @param lon Latitude to center at
2376  *
2377  * @ingroup Map
2378  */
2379 EAPI void
2380 elm_map_geo_region_bring_in(Evas_Object *obj, double lon, double lat)
2381 {
2382    ELM_CHECK_WIDTYPE(obj, widtype);
2383    Widget_Data *wd = elm_widget_data_get(obj);
2384    int rx, ry, rw, rh;
2385
2386    if (!wd) return;
2387    elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
2388    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
2389
2390    rx = rx - rw / 2;
2391    ry = ry - rh / 2;
2392
2393    if (wd->zoom_animator)
2394      {
2395         wd->nosmooth--;
2396         if (wd->nosmooth == 0) _smooth_update(obj);
2397         ecore_animator_del(wd->zoom_animator);
2398         wd->zoom_animator = NULL;
2399         zoom_do(obj, 1.0);
2400         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
2401      }
2402    elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh);
2403
2404    wd->center_on.enabled = EINA_TRUE;
2405    wd->center_on.lon = lon;
2406    wd->center_on.lat = lat;
2407 }
2408
2409 /**
2410  * Move the map to the current coordinates.
2411  *
2412  * This move the map to the current coordinates. The map will be centered on these coordinates.
2413  *
2414  * @param obj The map object
2415  * @param lat The latitude.
2416  * @param lon The longitude.
2417  *
2418  * @ingroup Map
2419  */
2420 EAPI void
2421 elm_map_geo_region_show(Evas_Object *obj, double lon, double lat)
2422 {
2423    ELM_CHECK_WIDTYPE(obj, widtype);
2424    Widget_Data *wd = elm_widget_data_get(obj);
2425    int rx, ry, rw, rh;
2426
2427    if (!wd) return;
2428    elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
2429    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
2430
2431    rx = rx - rw / 2;
2432    ry = ry - rh / 2;
2433
2434    if (wd->zoom_animator)
2435      {
2436         wd->nosmooth--;
2437         ecore_animator_del(wd->zoom_animator);
2438         wd->zoom_animator = NULL;
2439         zoom_do(obj, 1.0);
2440         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
2441      }
2442    elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh);
2443
2444    wd->center_on.enabled = EINA_TRUE;
2445    wd->center_on.lon = lon;
2446    wd->center_on.lat = lat;
2447 }
2448
2449 /**
2450  * Get the current coordinates of the map.
2451  *
2452  * This gets the current coordinates of the map object.
2453  *
2454  * @param obj The map object
2455  * @param lat The latitude.
2456  * @param lon The longitude.
2457  *
2458  * @ingroup Map
2459  */
2460 EAPI void
2461 elm_map_geo_region_get(const Evas_Object *obj, double *lon, double *lat)
2462 {
2463    ELM_CHECK_WIDTYPE(obj, widtype);
2464    Widget_Data *wd = elm_widget_data_get(obj);
2465    Evas_Coord sx, sy, sw, sh;
2466
2467    if (!wd) return;
2468    elm_smart_scroller_child_pos_get(wd->scr, &sx, &sy);
2469    elm_smart_scroller_child_viewport_size_get(wd->scr, &sw, &sh);
2470    sx += sw / 2;
2471    sy += sh / 2;
2472
2473    elm_map_utils_convert_coord_into_geo(obj, sx, sy, wd->size.w, lon, lat);
2474 }
2475
2476 /**
2477  * Set the paused state for map
2478  *
2479  * This sets the paused state to on (1) or off (0) for map. The default
2480  * is off. This will stop zooming using animation change zoom levels and
2481  * change instantly. This will stop any existing animations that are running.
2482  *
2483  * @param obj The map object
2484  * @param paused The pause state to set
2485  *
2486  * @ingroup Map
2487  */
2488 EAPI void
2489 elm_map_paused_set(Evas_Object *obj, Eina_Bool paused)
2490 {
2491    ELM_CHECK_WIDTYPE(obj, widtype);
2492    Widget_Data *wd = elm_widget_data_get(obj);
2493    if (!wd) return;
2494    if (wd->paused == !!paused) return;
2495    wd->paused = paused;
2496    if (wd->paused)
2497      {
2498         if (wd->zoom_animator)
2499           {
2500              ecore_animator_del(wd->zoom_animator);
2501              wd->zoom_animator = NULL;
2502              zoom_do(obj, 1.0);
2503              evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
2504           }
2505      }
2506 }
2507
2508 /**
2509  * Set the paused state for the markers
2510  *
2511  * This sets the paused state to on (1) or off (0) for the markers. The default
2512  * is off. This will stop displaying the markers during change zoom levels. Set
2513  * to on if you have a large number of markers.
2514  *
2515  * @param obj The map object
2516  * @param paused The pause state to set
2517  *
2518  * @ingroup Map
2519  */
2520 EAPI void
2521 elm_map_paused_markers_set(Evas_Object *obj, Eina_Bool paused)
2522 {
2523    ELM_CHECK_WIDTYPE(obj, widtype);
2524    Widget_Data *wd = elm_widget_data_get(obj);
2525    if (!wd) return;
2526    if (wd->paused_markers == !!paused) return;
2527    wd->paused_markers = paused;
2528 }
2529
2530 /**
2531  * Get the paused state for map
2532  *
2533  * This gets the current paused state for the map object.
2534  *
2535  * @param obj The map object
2536  * @return The current paused state
2537  *
2538  * @ingroup Map
2539  */
2540 EAPI Eina_Bool
2541 elm_map_paused_get(const Evas_Object *obj)
2542 {
2543    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2544    Widget_Data *wd = elm_widget_data_get(obj);
2545    if (!wd) return EINA_FALSE;
2546    return wd->paused;
2547 }
2548
2549 /**
2550  * Get the paused state for the markers
2551  *
2552  * This gets the current paused state for the markers object.
2553  *
2554  * @param obj The map object
2555  * @return The current paused state
2556  *
2557  * @ingroup Map
2558  */
2559 EAPI Eina_Bool
2560 elm_map_paused_markers_get(const Evas_Object *obj)
2561 {
2562    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2563    Widget_Data *wd = elm_widget_data_get(obj);
2564    if (!wd) return EINA_FALSE;
2565    return wd->paused_markers;
2566 }
2567
2568 /**
2569  * Convert a pixel coordinate (x,y) into a geographic coordinate (longitude, latitude).
2570  *
2571  * @param obj The map object
2572  * @param x the coordinate
2573  * @param y the coordinate
2574  * @param size the size in pixels of the map. The map is a square and generally his size is : pow(2.0, zoom)*256.
2575  * @param lon the longitude correspond to x
2576  * @param lat the latitude correspond to y
2577  *
2578  * @ingroup Map
2579  */
2580 EAPI void
2581 elm_map_utils_convert_coord_into_geo(const Evas_Object *obj, int x, int y, int size, double *lon, double *lat)
2582 {
2583    Widget_Data *wd = elm_widget_data_get(obj);
2584    int zoom = floor(log2(size/256));
2585
2586    if(map_sources_tab[elm_map_source_get(obj)].use_module == EINA_TRUE)
2587    if(wd->api) if ((wd->api) && (wd->api->obj_convert_coord_into_geo)){
2588       if(wd->api->obj_convert_coord_into_geo(obj, zoom, x, y, size, lon, lat)==EINA_TRUE)
2589          return;
2590    }
2591
2592    if (lon)
2593      {
2594         *lon = x / (double)size * 360.0 - 180;
2595      }
2596    if (lat)
2597      {
2598         double n = ELM_PI - 2.0 * ELM_PI * y / size;
2599         *lat = 180.0 / ELM_PI * atan(0.5 * (exp(n) - exp(-n)));
2600      }
2601 }
2602
2603 /**
2604  * Convert a geographic coordinate (longitude, latitude) into a pixel coordinate (x, y).
2605  *
2606  * @param obj The map object
2607  * @param lon the longitude
2608  * @param lat the latitude
2609  * @param size the size in pixels of the map. The map is a square and generally his size is : pow(2.0, zoom)*256.
2610  * @param x the coordinate correspond to the longitude
2611  * @param y the coordinate correspond to the latitude
2612  *
2613  * @ingroup Map
2614  */
2615 EAPI void
2616 elm_map_utils_convert_geo_into_coord(const Evas_Object *obj, double lon, double lat, int size, int *x, int *y)
2617 {
2618    Widget_Data *wd = elm_widget_data_get(obj);
2619    int zoom = floor(log2(size/256));
2620
2621    if(map_sources_tab[elm_map_source_get(obj)].use_module == EINA_TRUE)
2622    if(wd->api) if ((wd->api) && (wd->api->obj_convert_geo_into_coord)){
2623       if(wd->api->obj_convert_geo_into_coord(obj, zoom, lon, lat, size, x, y)==EINA_TRUE)
2624          return;
2625    }
2626
2627    if (x)
2628      *x = floor((lon + 180.0) / 360.0 * size);
2629    if (y)
2630      *y = floor((1.0 - log( tan(lat * ELM_PI/180.0) + 1.0 / cos(lat * ELM_PI/180.0)) / ELM_PI) / 2.0 * size);
2631 }
2632
2633
2634
2635 /**
2636  * Add a marker on the map
2637  *
2638  * @param obj The map object
2639  * @param lon the longitude
2640  * @param lat the latitude
2641  * @param clas the class to use
2642  * @param data the data passed to the callbacks
2643  *
2644  * @return The marker object
2645  *
2646  * @ingroup Map
2647  */
2648 EAPI Elm_Map_Marker *
2649 elm_map_marker_add(Evas_Object *obj, double lon, double lat, Elm_Map_Marker_Class *clas, Elm_Map_Group_Class *clas_group, void *data)
2650 {
2651    int i, j;
2652    Eina_List *l;
2653    Marker_Group *group;
2654    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2655    Widget_Data *wd = elm_widget_data_get(obj);
2656    int mpi, mpj;
2657    int tabi[9];
2658    int tabj[9];
2659    const char *s;
2660    const char *style;
2661    Evas_Object *o;
2662
2663    if (!wd) return NULL;
2664    if (!clas_group || !clas) return NULL;
2665
2666    Elm_Map_Marker *marker = ELM_NEW(Elm_Map_Marker);
2667
2668    marker->wd = wd;
2669    marker->clas = clas;
2670    marker->clas_group = clas_group;
2671    marker->longitude = lon;
2672    marker->latitude = lat;
2673    marker->data = data;
2674
2675    tabi[1] = tabi[4] = tabi[6] = -1;
2676    tabi[2] = tabi[0] = tabi[7] = 0;
2677    tabi[3] = tabi[5] = tabi[8] = 1;
2678
2679    tabj[1] = tabj[2] = tabj[3] = -1;
2680    tabj[4] = tabj[0] = tabj[5] = 0;
2681    tabj[6] = tabj[7] = tabj[8] = 1;
2682
2683    if (!clas_group->priv.set)
2684      {
2685         style = "radio";
2686         if (marker->clas_group && marker->clas_group->style)
2687           style = marker->clas_group->style;
2688
2689         o = edje_object_add(evas_object_evas_get(obj));
2690         _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
2691         s = edje_object_data_get(o, "size_w");
2692         clas_group->priv.edje_w = atoi(s);
2693         s = edje_object_data_get(o, "size_h");
2694         clas_group->priv.edje_h = atoi(s);
2695         s = edje_object_data_get(o, "size_max_w");
2696         clas_group->priv.edje_max_w = atoi(s);
2697         s = edje_object_data_get(o, "size_max_h");
2698         clas_group->priv.edje_max_h = atoi(s);
2699         evas_object_del(o);
2700
2701         clas_group->priv.set = EINA_TRUE;
2702      }
2703
2704    if (!clas->priv.set)
2705      {
2706         style = "radio";
2707         if (marker->clas && marker->clas->style)
2708           style = marker->clas->style;
2709         
2710         o = edje_object_add(evas_object_evas_get(obj));
2711         _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
2712         s = edje_object_data_get(o, "size_w");
2713         clas->priv.edje_w = atoi(s);
2714         s = edje_object_data_get(o, "size_h");
2715         clas->priv.edje_h = atoi(s);
2716         evas_object_del(o);
2717
2718         clas->priv.set = EINA_TRUE;
2719      }
2720
2721    for (i = clas_group->zoom_displayed; i <= ZOOM_MAX; i++)
2722      {
2723         elm_map_utils_convert_geo_into_coord(obj, lon, lat, pow(2.0, i)*wd->tsize,
2724                                              &(marker->x[i]), &(marker->y[i]));
2725         
2726         //search in the matrixsparse the region where the marker will be
2727         mpi = marker->x[i] / wd->tsize;
2728         mpj = marker->y[i] / wd->tsize;
2729
2730         if (!wd->markers[i])
2731           {
2732              int size =  pow(2.0, i);
2733              wd->markers[i] = eina_matrixsparse_new(size, size, NULL, NULL);
2734           }
2735
2736         group = NULL;
2737         if (i <= clas_group->zoom_grouped)
2738           {
2739              for (j = 0, group = NULL; j < 9 && !group; j++)
2740                {
2741                   EINA_LIST_FOREACH(eina_matrixsparse_data_idx_get(wd->markers[i], mpj + tabj[j], mpi + tabi[j]),
2742                                     l, group)
2743                     {
2744                        if (group->clas == marker->clas_group
2745                            && ELM_RECTS_INTERSECT(marker->x[i]-clas->priv.edje_w/4,
2746                                                   marker->y[i]-clas->priv.edje_h/4, clas->priv.edje_w, clas->priv.edje_h,
2747                                                   group->x-group->w/4, group->y-group->h/4, group->w, group->h))
2748                          {
2749                             group->markers = eina_list_append(group->markers, marker);
2750                             group->update_nbelems = EINA_TRUE;
2751                             group->update_resize = EINA_TRUE;
2752
2753                             group->sum_x += marker->x[i];
2754                             group->sum_y += marker->y[i];
2755                             group->x = group->sum_x / eina_list_count(group->markers);
2756                             group->y = group->sum_y / eina_list_count(group->markers);
2757
2758                             group->w = group->clas->priv.edje_w + group->clas->priv.edje_w/8.
2759                               * eina_list_count(group->markers);
2760                             group->h = group->clas->priv.edje_h + group->clas->priv.edje_h/8.
2761                               * eina_list_count(group->markers);
2762                             if (group->w > group->clas->priv.edje_max_w) group->w = group->clas->priv.edje_max_w;
2763                             if (group->h > group->clas->priv.edje_max_h) group->h = group->clas->priv.edje_max_h;
2764
2765                             if (group->obj && eina_list_count(group->markers) == 2)
2766                               {
2767                                  _group_object_free(group);
2768                                  _group_object_create(group);
2769                               }
2770                             if (group->bubble)
2771                               _group_bubble_content_update(group);
2772                             
2773                             break;
2774                          }
2775                     }
2776                }
2777           }
2778         if (!group)
2779           {
2780              group = calloc(1, sizeof(Marker_Group));
2781              group->wd = wd;
2782              group->sum_x = marker->x[i];
2783              group->sum_y = marker->y[i];
2784              group->x = marker->x[i];
2785              group->y = marker->y[i];
2786              group->w = clas_group->priv.edje_w;
2787              group->h = clas_group->priv.edje_h;
2788              group->clas = clas_group;
2789
2790              group->markers = eina_list_append(group->markers, marker);
2791              group->update_nbelems = EINA_TRUE;
2792              group->update_resize = EINA_TRUE;
2793
2794              eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
2795
2796              if (!group->cell)
2797                {
2798                   l = eina_list_append(NULL, group);
2799                   eina_matrixsparse_data_idx_set(wd->markers[i], mpj, mpi, l);
2800                   eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
2801                }
2802              else
2803                {
2804                   l = eina_matrixsparse_cell_data_get(group->cell);
2805                   l = eina_list_append(l, group);
2806                   eina_matrixsparse_cell_data_set(group->cell, l);
2807                }
2808           }
2809         marker->groups[i] = group;
2810      }
2811
2812    if (wd->grids)
2813      {
2814         Evas_Coord ox, oy, ow, oh;
2815         evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
2816         marker_place(obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
2817      }
2818
2819    return marker;
2820 }
2821
2822 /**
2823  * Remove a marker from the map
2824  *
2825  * @param marker The marker to remove
2826  *
2827  * @ingroup Map
2828  */
2829 EAPI void
2830 elm_map_marker_remove(Elm_Map_Marker *marker)
2831 {
2832    int i;
2833    Eina_List *groups;
2834    Widget_Data *wd;
2835
2836    if (!marker) return;
2837    wd = marker->wd;
2838    if (!wd) return;
2839    for (i = 0; i <= ZOOM_MAX; i++)
2840      {
2841         marker->groups[i]->markers = eina_list_remove(marker->groups[i]->markers, marker);
2842         if (eina_list_count(marker->groups[i]->markers) == 0)
2843           {
2844              groups = eina_matrixsparse_cell_data_get(marker->groups[i]->cell);
2845              groups = eina_list_remove(groups, marker->groups[i]);
2846              eina_matrixsparse_cell_data_set(marker->groups[i]->cell, groups);
2847              
2848              _group_object_free(marker->groups[i]);
2849              _group_bubble_free(marker->groups[i]);
2850              free(marker->groups[i]);
2851           }
2852         else
2853           {
2854              marker->groups[i]->sum_x -= marker->x[i];
2855              marker->groups[i]->sum_y -= marker->y[i];
2856              
2857              marker->groups[i]->x = marker->groups[i]->sum_x / eina_list_count(marker->groups[i]->markers);
2858              marker->groups[i]->y = marker->groups[i]->sum_y / eina_list_count(marker->groups[i]->markers);
2859              
2860              marker->groups[i]->w = marker->groups[i]->clas->priv.edje_w
2861                + marker->groups[i]->clas->priv.edje_w/8. * eina_list_count(marker->groups[i]->markers);
2862              marker->groups[i]->h = marker->groups[i]->clas->priv.edje_h
2863                + marker->groups[i]->clas->priv.edje_h/8. * eina_list_count(marker->groups[i]->markers);
2864              if (marker->groups[i]->w > marker->groups[i]->clas->priv.edje_max_w)
2865                marker->groups[i]->w = marker->groups[i]->clas->priv.edje_max_w;
2866              if (marker->groups[i]->h > marker->groups[i]->clas->priv.edje_max_h)
2867                marker->groups[i]->h = marker->groups[i]->clas->priv.edje_max_h;
2868           }
2869         if (marker->groups[i]->obj && eina_list_count(marker->groups[i]->markers) == 1)
2870           {
2871              _group_object_free(marker->groups[i]);
2872              _group_object_create(marker->groups[i]);
2873           }
2874      }
2875
2876    if (marker->content && marker->clas->func.del)
2877      marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
2878    else if (marker->content)
2879      evas_object_del(marker->content);
2880    
2881    free(marker);
2882    
2883    if (wd->grids)
2884      {
2885         Evas_Coord ox, oy, ow, oh;
2886         evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
2887         marker_place(wd->obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
2888      }
2889 }
2890
2891 /**
2892  * Move the map to the coordinate of the marker.
2893  *
2894  * @param marker The marker where the map will be center.
2895  *
2896  * @ingroup Map
2897  */
2898 EAPI void
2899 elm_map_marker_bring_in(Elm_Map_Marker *marker)
2900 {
2901    if (!marker) return;
2902    elm_map_geo_region_bring_in(marker->wd->obj, marker->longitude, marker->latitude);
2903 }
2904
2905
2906 /**
2907  * Move the map to the coordinate of the marker.
2908  *
2909  * @param marker The marker where the map will be center.
2910  *
2911  * @ingroup Map
2912  */
2913 EAPI void
2914 elm_map_marker_show(Elm_Map_Marker *marker)
2915 {
2916    if (!marker) return;
2917    elm_map_geo_region_show(marker->wd->obj, marker->longitude, marker->latitude);
2918 }
2919
2920 /**
2921  * Move and zoom the map to display a list of markers.
2922  *
2923  * The map will be centered on the center point of the markers in the list. Then
2924  * the map will be zoomed in order to fit the markers using the maximum zoom which
2925  * allows display of all the markers.
2926  *
2927  * @param markers The list of markers (list of Elm_Map_Marker *)
2928  *
2929  * @ingroup Map
2930  */
2931 EAPI void
2932 elm_map_markers_list_show(Eina_List *markers)
2933 {
2934    int zoom;
2935    double lon, lat;
2936    Eina_List *l;
2937    Elm_Map_Marker *marker, *m_max_lon = NULL, *m_max_lat = NULL, *m_min_lon = NULL, *m_min_lat = NULL;
2938    Evas_Coord rw, rh, xc, yc;
2939    Widget_Data *wd;
2940
2941    if (!markers) return;
2942
2943    EINA_LIST_FOREACH(markers, l, marker)
2944      {
2945         wd = marker->wd;
2946
2947         if (!m_min_lon || marker->longitude < m_min_lon->longitude)
2948           m_min_lon = marker;
2949         
2950         if (!m_max_lon || marker->longitude > m_max_lon->longitude)
2951           m_max_lon = marker;
2952         
2953         if (!m_min_lat || marker->latitude > m_min_lat->latitude)
2954           m_min_lat = marker;
2955         
2956         if (!m_max_lat || marker->latitude < m_max_lat->latitude)
2957           m_max_lat = marker;
2958      }
2959    
2960    lon = (m_max_lon->longitude - m_min_lon->longitude) / 2. + m_min_lon->longitude;
2961    lat = (m_max_lat->latitude - m_min_lat->latitude) / 2. + m_min_lat->latitude;
2962    
2963    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
2964    for (zoom = map_sources_tab[wd->source].zoom_max; zoom>map_sources_tab[wd->source].zoom_min; zoom--)
2965      {
2966         Evas_Coord size = pow(2.0, zoom)*wd->tsize;
2967         elm_map_utils_convert_geo_into_coord(wd->obj, lon, lat, size, &xc, &yc);
2968         
2969         if (m_min_lon->x[zoom] - wd->marker_max_w >= xc-rw/2
2970             && m_min_lat->y[zoom] - wd->marker_max_h >= yc-rh/2
2971             && m_max_lon->x[zoom] + wd->marker_max_w <= xc+rw/2
2972             && m_max_lat->y[zoom] + wd->marker_max_h <= yc+rh/2)
2973           break;
2974      }
2975
2976    elm_map_geo_region_show(wd->obj, lon, lat);
2977    elm_map_zoom_set(wd->obj, zoom);
2978 }
2979
2980 /**
2981  * Set the maximum numbers of markers display in a group.
2982  *
2983  * A group can have a long list of markers, consequently the creation of the content
2984  * of the bubble can be very slow. In order to avoid this, a maximum number of items
2985  * is displayed in a bubble. By default this number is 30.
2986  *
2987  * @param obj The map object.
2988  * @param max The maximum numbers of items displayed in a bubble.
2989  *
2990  * @ingroup Map
2991  */
2992 EAPI void
2993 elm_map_max_marker_per_group_set(Evas_Object *obj, int max)
2994 {
2995    ELM_CHECK_WIDTYPE(obj, widtype);
2996    Widget_Data *wd = elm_widget_data_get(obj);
2997    if (!wd) return;
2998    wd->markers_max_num = max;
2999 }
3000
3001 /**
3002  * Return the evas object getting from the ElmMapMarkerGetFunc callback
3003  *
3004  * @param marker The marker.
3005  * @return Return the evas object if it exists, else NULL.
3006  *
3007  * @ingroup Map
3008  */
3009 EAPI Evas_Object *
3010 elm_map_marker_object_get(Elm_Map_Marker *marker)
3011 {
3012    if (!marker) return NULL;
3013    return marker->content;
3014 }
3015
3016 /**
3017  * Update the marker
3018  *
3019  * @param marker The marker.
3020  *
3021  * @ingroup Map
3022  */
3023 EAPI void
3024 elm_map_marker_update(Elm_Map_Marker *marker)
3025 {
3026    if (!marker) return;
3027    if (marker->content)
3028      {
3029         if (marker->clas->func.del)
3030           marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
3031         else
3032           evas_object_del(marker->content);
3033         marker->content = NULL;
3034         _group_bubble_content_update(marker->groups[marker->wd->zoom]);
3035      }
3036 }
3037
3038 /**
3039  * Close all opened bubbles
3040  *
3041  * @param obj The map object
3042  *
3043  * @ingroup Map
3044  */
3045 EAPI void
3046 elm_map_bubbles_close(Evas_Object *obj)
3047 {
3048    ELM_CHECK_WIDTYPE(obj, widtype);
3049    Widget_Data *wd = elm_widget_data_get(obj);
3050    Marker_Group *group;
3051    Eina_List *l, *l_next;
3052    if (!wd) return;
3053    EINA_LIST_FOREACH_SAFE(wd->opened_bubbles, l, l_next, group)
3054      _group_bubble_free(group);
3055 }
3056
3057
3058 /**
3059  * Create a group class.
3060  *
3061  * Each marker must be associated to a group class. Marker with the same group are grouped if they are close.
3062  * The group class defines the style of the marker when a marker is grouped to others markers.
3063  *
3064  * @param obj The map object
3065  * @return Returns the new group class
3066  *
3067  * @ingroup Map
3068  */
3069 EAPI Elm_Map_Group_Class *
3070 elm_map_group_class_new(Evas_Object *obj)
3071 {
3072    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3073    Widget_Data *wd = elm_widget_data_get(obj);
3074    if (!wd) return NULL;
3075    Elm_Map_Group_Class *clas = calloc(1, sizeof(Elm_Map_Group_Class));
3076    clas->zoom_grouped = ZOOM_MAX;
3077    wd->groups_clas = eina_list_append(wd->groups_clas, clas);
3078    return clas;
3079 }
3080
3081 /**
3082  * Set the style of a group class (radio, radio2 or empty)
3083  *
3084  * @param clas the group class
3085  * @param style the new style
3086  *
3087  * @ingroup Map
3088  */
3089 EAPI void
3090 elm_map_group_class_style_set(Elm_Map_Group_Class *clas, const char *style)
3091 {
3092    if (!clas) return;
3093    eina_stringshare_replace(&clas->style, style);
3094 }
3095
3096 /**
3097  * Set the icon callback of a group class.
3098  *
3099  * A custom icon can be displayed in a marker. The function @ref icon_get must return this icon.
3100  *
3101  * @param clas the group class
3102  * @param icon_get the callback to create the icon
3103  *
3104  * @ingroup Map
3105  */
3106 EAPI void
3107 elm_map_group_class_icon_cb_set(Elm_Map_Group_Class *clas, ElmMapGroupIconGetFunc icon_get)
3108 {
3109    if (!clas) return;
3110    clas->func.icon_get = icon_get;
3111 }
3112
3113 /**
3114  * Set the data associated to the group class (radio, radio2 or empty)
3115  *
3116  * @param clas the group class
3117  * @param data the new user data
3118  *
3119  * @ingroup Map
3120  */
3121 EAPI void
3122 elm_map_group_class_data_set(Elm_Map_Group_Class *clas, void *data)
3123 {
3124    if (!clas) return;
3125    clas->data = data;
3126 }
3127
3128 /**
3129  * Set the zoom from where the markers are displayed.
3130  *
3131  * Markers will not be displayed for a zoom less than @ref zoom
3132  *
3133  * @param clas the group class
3134  * @param zoom the zoom
3135  *
3136  * @ingroup Map
3137  */
3138 EAPI void
3139 elm_map_group_class_zoom_displayed_set(Elm_Map_Group_Class *clas, int zoom)
3140 {
3141    if (!clas) return;
3142    clas->zoom_displayed = zoom;
3143 }
3144
3145 /**
3146  * Set the zoom from where the markers are no more grouped.
3147  *
3148  * @param clas the group class
3149  * @param zoom the zoom
3150  *
3151  * @ingroup Map
3152  */
3153 EAPI void
3154 elm_map_group_class_zoom_grouped_set(Elm_Map_Group_Class *clas, int zoom)
3155 {
3156    if (!clas) return;
3157    clas->zoom_grouped = zoom;
3158 }
3159
3160 /**
3161  * Set if the markers associated to the group class @clas are hidden or not.
3162  * If @ref hide is true the markers will be hidden.
3163  *
3164  * @param clas the group class
3165  * @param hide if true the markers will be hidden, else they will be displayed.
3166  *
3167  * @ingroup Map
3168  */
3169 EAPI void
3170 elm_map_group_class_hide_set(Evas_Object *obj, Elm_Map_Group_Class *clas, Eina_Bool hide)
3171 {
3172    ELM_CHECK_WIDTYPE(obj, widtype);
3173    Widget_Data *wd = elm_widget_data_get(obj);
3174    if (!wd) return;
3175    if (!clas) return;
3176    if (clas->hide == hide) return;
3177    clas->hide = hide;
3178    if (wd->grids)
3179      {
3180         Evas_Coord ox, oy, ow, oh;
3181         evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
3182         marker_place(obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
3183      }
3184 }
3185
3186
3187 /**
3188  * Create a marker class.
3189  *
3190  * Each marker must be associated to a class.
3191  * The class defines the style of the marker when a marker is displayed alone (not grouped).
3192  *
3193  * @param obj The map object
3194  * @return Returns the new class
3195  *
3196  * @ingroup Map
3197  */
3198 EAPI Elm_Map_Marker_Class *
3199 elm_map_marker_class_new(Evas_Object *obj)
3200 {
3201    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3202    Widget_Data *wd = elm_widget_data_get(obj);
3203    if (!wd) return NULL;
3204    Elm_Map_Marker_Class *clas = calloc(1, sizeof(Elm_Map_Marker_Class));
3205    wd->markers_clas = eina_list_append(wd->markers_clas, clas);
3206    return clas;
3207 }
3208
3209 /**
3210  * Set the style of a class (radio, radio2 or empty)
3211  *
3212  * @param clas the group class
3213  * @param style the new style
3214  *
3215  * @ingroup Map
3216  */
3217 EAPI void
3218 elm_map_marker_class_style_set(Elm_Map_Marker_Class *clas, const char *style)
3219 {
3220    if (!clas) return;
3221    eina_stringshare_replace(&clas->style, style);
3222 }
3223
3224 /**
3225  * Set the icon callback of a class.
3226  *
3227  * A custom icon can be displayed in a marker. The function @ref icon_get must return this icon.
3228  *
3229  * @param clas the group class
3230  * @param icon_get the callback to create the icon
3231  *
3232  * @ingroup Map
3233  */
3234 EAPI void
3235 elm_map_marker_class_icon_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerIconGetFunc icon_get)
3236 {
3237    if (!clas) return;
3238    clas->func.icon_get = icon_get;
3239 }
3240
3241 /**
3242  *
3243  * Set the callback of the content of the bubble.
3244  *
3245  * When the user click on a marker, a bubble is displayed with a content.
3246  * The callback @ref get musst return this content. It can be NULL.
3247  *
3248  * @param clas the group class
3249  * @param get the callback to create the content
3250  *
3251  * @ingroup Map
3252  */
3253 EAPI void
3254 elm_map_marker_class_get_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerGetFunc get)
3255 {
3256    if (!clas) return;
3257    clas->func.get = get;
3258 }
3259
3260 /**
3261  * Set the callback of the content of delete the object created by the callback "get".
3262  *
3263  * If this callback is defined the user will have to delete (or not) the object inside.
3264  * If the callback is not defined the object will be destroyed with evas_object_del()
3265  *
3266  * @param clas the group class
3267  * @param del the callback to delete the content
3268  *
3269  * @ingroup Map
3270  */
3271 EAPI void
3272 elm_map_marker_class_del_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerDelFunc del)
3273 {
3274    if (!clas) return;
3275    clas->func.del = del;
3276 }
3277
3278 /**
3279  * Set the source of the map.
3280  *
3281  * Elm_Map retrieves the image which composed the map from a web service. This web service can
3282  * be set with this method. A different service can return a different maps with different
3283  * information and it can use different zoom value.
3284  *
3285  * @param clas the group class
3286  * @param source the new source
3287  *
3288  * @ingroup Map
3289  */
3290 EAPI void
3291 elm_map_source_set(Evas_Object *obj, Elm_Map_Sources source)
3292 {
3293    ELM_CHECK_WIDTYPE(obj, widtype);
3294    Widget_Data *wd = elm_widget_data_get(obj);
3295    Grid *grid;
3296    int zoom;
3297    if (!wd) return;
3298    if (wd->source == source ) return;
3299    if (!map_sources_tab[source].url_cb) return;
3300
3301    EINA_LIST_FREE(wd->grids, grid) grid_clear(obj, grid);
3302
3303    wd->source = source;
3304    zoom = wd->zoom;
3305    wd->zoom = -1;
3306
3307    if (map_sources_tab[wd->source].zoom_max < zoom)
3308      zoom = map_sources_tab[wd->source].zoom_max;
3309    if (map_sources_tab[wd->source].zoom_min > zoom)
3310      zoom = map_sources_tab[wd->source].zoom_min;
3311    
3312    elm_map_zoom_set(obj, zoom);
3313 }
3314
3315 /**
3316  * Get the current source
3317  *
3318  * @param obj the map object
3319  * @return Returns the maximum zoom of the source
3320  *
3321  * @ingroup Map
3322  */
3323 EAPI Elm_Map_Sources
3324 elm_map_source_get(const Evas_Object *obj)
3325 {
3326    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_SOURCE_MAPNIK;
3327    Widget_Data *wd = elm_widget_data_get(obj);
3328    if (!wd) return ELM_MAP_SOURCE_MAPNIK;
3329    return wd->source;
3330 }
3331
3332 /**
3333  * Set the API of a custom source.
3334  *
3335  * A custom web service can be associated to the source ELM_MAP_SOURCE_CUSTOM_(1..7).
3336  *
3337  * @param source the source ID (ELM_MAP_SOURCE_CUSTOM_(1..7))
3338  * @param name the name of the source
3339  * @param zoom_min the minimum zoom of the source, must be >= 0
3340  * @param zoom_max the maximum zoom of the source, must be <= ZOOM_MAX
3341  * @param url_cb the callback used to create the url from where a tile (png or jpeg file) is downloaded.
3342  *
3343  * @ingroup Map
3344  */
3345 EAPI void
3346 elm_map_source_custom_api_set(Elm_Map_Sources source, const char *name, int zoom_min, int zoom_max, ElmMapSourceURLFunc url_cb)
3347 {
3348    if (!name || !url_cb) return;
3349    map_sources_tab[source].name = name;
3350    map_sources_tab[source].zoom_min = zoom_min;
3351    map_sources_tab[source].zoom_max = zoom_max;
3352    map_sources_tab[source].url_cb = url_cb;
3353 }
3354
3355 /**
3356  * Get the maximum zoom of the source.
3357  *
3358  * @param source the source
3359  * @return Returns the maximum zoom of the source
3360  *
3361  * @ingroup Map
3362  */
3363 EAPI int
3364 elm_map_source_zoom_max_get(Elm_Map_Sources source)
3365 {
3366    return map_sources_tab[source].zoom_max;
3367 }
3368
3369 /**
3370  * Get the minimum zoom of the source.
3371  *
3372  * @param source the source
3373  * @return Returns the minimum zoom of the source
3374  *
3375  * @ingroup Map
3376  */
3377 EAPI int
3378 elm_map_source_zoom_min_get(Elm_Map_Sources source)
3379 {
3380    return map_sources_tab[source].zoom_min;
3381 }
3382
3383 /**
3384  * Get the name of a source.
3385  *
3386  * @param source the source
3387  * @return Returns the name of the source
3388  *
3389  * @ingroup Map
3390  */
3391 EAPI const char *
3392 elm_map_source_name_get(Elm_Map_Sources source)
3393 {
3394    return map_sources_tab[source].name;
3395 }
3396
3397
3398 static char *
3399 _mapnik_url_cb(void *data, int x, int y, int zoom)
3400 {
3401    char buf[PATH_MAX];
3402    snprintf(buf, sizeof(buf), "http://tile.openstreetmap.org/%d/%d/%d.png",
3403             zoom, x, y);
3404    return strdup(buf);
3405 }
3406
3407 static char *
3408 _osmarender_url_cb(void * data, int x, int y, int zoom)
3409 {
3410    char buf[PATH_MAX];
3411    snprintf(buf, sizeof(buf), "http://tah.openstreetmap.org/Tiles/tile/%d/%d/%d.png",
3412             zoom, x, y);
3413    return strdup(buf);
3414 }
3415
3416 static char *
3417 _cyclemap_url_cb(void *data, int x, int y, int zoom)
3418 {
3419    char buf[PATH_MAX];
3420    snprintf(buf, sizeof(buf), "http://andy.sandbox.cloudmade.com/tiles/cycle/%d/%d/%d.png",
3421             zoom, x, y);
3422    return strdup(buf);
3423 }
3424
3425 static char *
3426 _maplint_url_cb(void *data, int x, int y, int zoom)
3427 {
3428    char buf[PATH_MAX];
3429    snprintf(buf, sizeof(buf), "http://tah.openstreetmap.org/Tiles/maplint/%d/%d/%d.png",
3430             zoom, x, y);
3431    return strdup(buf);
3432 }
3433
3434 static char *
3435 _decarta_url_cb(void *data, int x, int y, int zoom)
3436 {
3437    char *url = NULL;
3438    Widget_Data *wd = elm_widget_data_get(data);
3439    if(map_sources_tab[elm_map_source_get(data)].use_module == EINA_TRUE)
3440    if(wd->api) if ((wd->api) && (wd->api->obj_url_request))
3441       url = wd->api->obj_url_request(data, x, y, zoom);
3442
3443    if(!url) url = strdup("");
3444
3445    return url;
3446 }
3447