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