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