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