688db52ec7a270baa076b3fd457ee40d2352995c
[framework/uifw/elementary.git] / src / lib / elm_map.c
1 #include <Elementary.h>
2 #include "Ecore_Con.h"
3 #include "Eina.h"
4 #include "elm_priv.h"
5
6 /**
7  * @defgroup Map Map
8  * @ingroup Elementary
9  *
10  * This is a widget specifically for displaying the map. It uses basically
11  * OpenStreetMap provider. but it can be added custom providers.
12  *
13  * Signals that you can add callbacks for are:
14  *
15  * "clicked" - This is called when a user has clicked the map without dragging
16  *             around.
17  *
18  * "press" - This is called when a user has pressed down on the map.
19  *
20  * "longpressed" - This is called when a user has pressed down on the map for
21  *                 a long time without dragging around.
22  *
23  * "clicked,double" - This is called when a user has double-clicked the map.
24  *
25  * "load,detail" - Map detailed data load begins.
26  *
27  * "loaded,detail" - This is called when all parts of the map are loaded.
28  *
29  * "zoom,start" - Zoom animation started.
30  *
31  * "zoom,stop" - Zoom animation stopped.
32  *
33  * "zoom,change" - Zoom changed when using an auto zoom mode.
34  *
35  * "scroll" - the content has been scrolled (moved)
36  *
37  * "scroll,anim,start" - scrolling animation has started
38  *
39  * "scroll,anim,stop" - scrolling animation has stopped
40  *
41  * "scroll,drag,start" - dragging the contents around has started
42  *
43  * "scroll,drag,stop" - dragging the contents around has stopped
44  *
45  * "downloaded" - This is called when map images are downloaded
46  *
47  * "route,load" - This is called when route request begins
48  *
49  * "route,loaded" - This is called when route request ends
50  *
51  * "name,load" - This is called when name request begins
52  *
53  * "name,loaded- This is called when name request ends
54  *
55  * TODO : doxygen
56  */
57
58
59 typedef struct _Widget_Data Widget_Data;
60 typedef struct _Pan Pan;
61 typedef struct _Grid Grid;
62 typedef struct _Grid_Item Grid_Item;
63 typedef struct _Marker_Group Marker_Group;
64 typedef struct _Event Event;
65 typedef struct _Route_Node Route_Node;
66 typedef struct _Route_Waypoint Route_Waypoint;
67 typedef struct _Url_Data Url_Data;
68 typedef struct _Route_Dump Route_Dump;
69 typedef struct _Name_Dump Name_Dump;
70
71 #define DEST_DIR_ZOOM_PATH "/tmp/elm_map/%d/%d/"
72 #define DEST_DIR_PATH DEST_DIR_ZOOM_PATH"%d/"
73 #define DEST_FILE_PATH "%s%d.png"
74 #define DEST_ROUTE_XML_FILE "/tmp/elm_map-route-XXXXXX"
75 #define DEST_NAME_XML_FILE "/tmp/elm_map-name-XXXXXX"
76
77 #define ROUTE_YOURS_URL "http://www.yournavigation.org/api/dev/route.php"
78 #define ROUTE_TYPE_MOTORCAR "motocar"
79 #define ROUTE_TYPE_BICYCLE "bicycle"
80 #define ROUTE_TYPE_FOOT "foot"
81 #define YOURS_DISTANCE "distance"
82 #define YOURS_DESCRIPTION "description"
83 #define YOURS_COORDINATES "coordinates"
84
85 // TODO: fix monav & ors url
86 #define ROUTE_MONAV_URL "http://"
87 #define ROUTE_ORS_URL "http:///"
88
89 #define NAME_NOMINATIM_URL "http://nominatim.openstreetmap.org"
90 #define NOMINATIM_RESULT "result"
91 #define NOMINATIM_PLACE "place"
92 #define NOMINATIM_ATTR_LON "lon"
93 #define NOMINATIM_ATTR_LAT "lat"
94
95 #define PINCH_ZOOM_MIN 0.1
96 #define PINCH_ZOOM_MAX 5.0
97
98 // Map sources
99 // Currently the size of a tile must be 256*256
100 // and the size of the map must be pow(2.0, z)*tile_size
101 typedef struct _Map_Sources_Tab
102 {
103    const char *name;
104    int zoom_min;
105    int zoom_max;
106    ElmMapModuleUrlFunc url_cb;
107    Elm_Map_Route_Sources route_source;
108    ElmMapModuleRouteUrlFunc route_url_cb;
109    ElmMapModuleNameUrlFunc name_url_cb;
110    ElmMapModuleGeoIntoCoordFunc geo_into_coord;
111    ElmMapModuleCoordIntoGeoFunc coord_into_geo;
112 } Map_Sources_Tab;
113
114 #define ZOOM_MAX 18
115
116 //Zemm min is supposed to be 0
117 static char *_mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
118 static char *_osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
119 static char *_cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
120 static char *_maplint_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
121
122 static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
123 /*
124 static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
125 static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
126  */
127 static char *_nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat);
128
129 static Map_Sources_Tab default_map_sources_tab[] =
130 {
131      {"Mapnik", 0, 18, _mapnik_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
132      {"Osmarender", 0, 17, _osmarender_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
133      {"CycleMap", 0, 17, _cyclemap_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
134      {"Maplint", 12, 16, _maplint_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
135 };
136
137 struct _Url_Data
138 {
139    Ecore_Con_Url *con_url;
140
141    FILE *fd;
142    char *fname;
143 };
144
145 struct _Elm_Map_Marker_Class
146 {
147    const char *style;
148    int zoom_displayed;
149
150    struct _Elm_Map_Marker_Class_Func {
151         ElmMapMarkerGetFunc get;
152         ElmMapMarkerDelFunc del; //if NULL the object will be destroyed with evas_object_del()
153         ElmMapMarkerIconGetFunc icon_get;
154    } func;
155
156    struct { //this part is private, do not modify these values
157         Eina_Bool set : 1;
158         Evas_Coord edje_w, edje_h;
159    } priv;
160 };
161
162 struct _Elm_Map_Marker
163 {
164    Widget_Data *wd;
165    Elm_Map_Marker_Class *clas;
166    Elm_Map_Group_Class *clas_group;
167    double longitude, latitude;
168
169    Evas_Coord map_size;
170    Evas_Coord x[ZOOM_MAX+1], y[ZOOM_MAX+1];
171    void *data;
172
173    Marker_Group *groups[ZOOM_MAX+1];
174
175    Evas_Object *content;
176 };
177
178 struct _Elm_Map_Group_Class
179 {
180    const char *style;
181    void *data;
182    int zoom_displayed; // display the group if the zoom is >= to zoom_display
183    int zoom_grouped; // group the markers only if the zoom is <= to zoom_groups
184    Eina_Bool hide : 1;
185
186    struct {
187         ElmMapGroupIconGetFunc icon_get;
188    } func;
189
190    struct { //this part is private, do not modify these values
191         Eina_Bool set : 1;
192         Evas_Coord edje_w, edje_h;
193         Evas_Coord edje_max_w, edje_max_h;
194
195         Eina_List *objs_used;
196         Eina_List *objs_notused;
197    } priv;
198 };
199
200 struct _Marker_Group
201 {
202    Widget_Data *wd;
203    Eina_Matrixsparse_Cell *cell;
204    Elm_Map_Group_Class *clas;
205
206    Eina_List *markers;
207    long long sum_x, sum_y;
208    Evas_Coord x, y;
209    Evas_Coord w, h;
210
211    Evas_Object *obj, *bubble, *sc, *bx, *rect;
212    Eina_Bool open : 1;
213    Eina_Bool bringin : 1;
214    Eina_Bool update_nbelems : 1;
215    Eina_Bool update_resize : 1;
216    Eina_Bool update_raise : 1;
217    Eina_Bool delete_object : 1;
218 };
219
220 struct _Elm_Map_Route
221 {
222    Widget_Data *wd;
223
224    Route_Node *n;
225    Route_Waypoint *w;
226    Ecore_Con_Url *con_url;
227
228    int type;
229    int method;
230    int x, y;
231    double flon, flat, tlon, tlat;
232
233    Eina_List *nodes, *path;
234    Eina_List *waypoint;
235
236    struct {
237       int node_count;
238       int waypoint_count;
239       const char *nodes;
240       const char *waypoints;
241       double distance; /* unit : km */
242    } info;
243
244    Eina_List *handlers;
245    Url_Data ud;
246
247    struct {
248       int r;
249       int g;
250       int b;
251       int a;
252    } color;
253
254    Eina_Bool inbound : 1;
255 };
256
257 struct _Route_Node
258 {
259    Widget_Data *wd;
260
261    int idx;
262    struct {
263       double lon, lat;
264       char *address;
265    } pos;
266 };
267
268 struct _Route_Waypoint
269 {
270    Widget_Data *wd;
271
272    const char *point;
273 };
274
275 struct _Elm_Map_Name
276 {
277    Widget_Data *wd;
278
279    Ecore_Con_Url *con_url;
280    int method;
281    char *address;
282    double lon, lat;
283    Url_Data ud;
284    Ecore_Event_Handler *handler;
285 };
286
287 struct _Grid_Item
288 {
289    Widget_Data *wd;
290    Evas_Object *img;
291    //Evas_Object *txt;
292    const char *file;
293    struct {
294         int x, y, w, h;
295    } src, out;
296    Eina_Bool want : 1;
297    Eina_Bool download : 1;
298    Eina_Bool have : 1;
299    Ecore_File_Download_Job *job;
300    int try_num;
301 };
302
303 struct _Grid
304 {
305    Widget_Data *wd;
306    int tsize; // size of tile (tsize x tsize pixels)
307    int zoom; // zoom level tiles want for optimal display (1, 2, 4, 8)
308    int iw, ih; // size of image in pixels
309    int w, h; // size of grid image in pixels (represented by grid)
310    int gw, gh; // size of grid in tiles
311    Eina_Matrixsparse *grid;
312 };
313
314 struct _Widget_Data
315 {
316    Evas_Object *obj;
317    Evas_Object *scr;
318    Evas_Object *pan_smart;
319    Evas_Object *rect;
320    Evas_Object *sep_maps_markers; //map objects are below this object and marker objects are on top
321    Pan *pan;
322    Evas_Coord pan_x, pan_y, minw, minh;
323
324    int id;
325    int zoom;
326    int zoom_method;
327    Elm_Map_Zoom_Mode mode;
328
329    Ecore_Job *calc_job;
330    Ecore_Timer *scr_timer;
331    Ecore_Timer *long_timer;
332    Ecore_Animator *zoom_animator;
333    double t;
334    struct {
335         int w, h;
336         int ow, oh, nw, nh;
337         struct {
338              double x, y;
339         } spos;
340    } size;
341    struct {
342         Eina_Bool show : 1;
343         Evas_Coord x, y ,w ,h;
344    } show;
345    int tsize;
346    int nosmooth;
347    int preload_num;
348    Eina_List *grids;
349    Eina_Bool resized : 1;
350    Eina_Bool on_hold : 1;
351    Eina_Bool paused : 1;
352    Eina_Bool paused_markers : 1;
353
354    struct {
355         Eina_Bool enabled;
356         double lon, lat;
357    } center_on;
358
359    Ecore_Job *markers_place_job;
360    Eina_Matrixsparse *markers[ZOOM_MAX+1];
361    Eina_List *cells_displayed; // list of Eina_Matrixsparse_Cell
362    Evas_Coord markers_max_num;
363    int marker_max_w, marker_max_h;
364    int marker_zoom;
365    Eina_List *opened_bubbles; //opened bubbles, list of Map_Group *
366
367    Eina_List *groups_clas; // list of Elm_Map_Group_Class*
368    Eina_List *markers_clas; // list of Elm_Map_Markers_Class*
369
370    Elm_Map_Route_Sources route_source;
371    Eina_List *s_event_list;
372    int try_num;
373    int finish_num;
374
375    Eina_Hash *ua;
376    const char *user_agent;
377    Eina_List *route;
378    Evas_Event_Mouse_Down ev;
379    Eina_List *names;
380    int multi_count;
381
382    struct {
383         Evas_Coord cx, cy;
384         double level, diff;
385    } pinch;
386
387    struct {
388         Evas_Coord cx, cy;
389         double a, d;
390    } rotate;
391
392    struct {
393         Evas_Coord cx, cy;
394         double level;
395    } pinch_zoom;
396    double wheel_zoom;
397    Ecore_Timer *wheel_timer;
398    Eina_Bool wheel_disabled : 1;
399
400    Eina_Array *modules;
401    Eina_List *map_sources_tab;
402    const char *source_name;
403    const char **source_names;
404    Evas_Map *map;
405    Ecore_Timer *zoom_timer;
406 };
407
408 struct _Pan
409 {
410    Evas_Object_Smart_Clipped_Data __clipped_data;
411    Widget_Data *wd;
412 };
413
414 struct _Event
415 {
416    int device;
417
418    struct {
419         Evas_Coord x, y;
420    } start;
421
422    struct {
423         Evas_Coord x, y;
424    } prev;
425
426    Evas_Coord x, y, w, h;
427
428    Evas_Object *object;
429    Ecore_Timer *hold_timer;
430
431    int pinch_start_dis;
432    int pinch_dis;
433 };
434
435 struct _Route_Dump
436 {
437    int id;
438    char *fname;
439    double distance;
440    char *description;
441    char *coordinates;
442 };
443
444 enum _Route_Xml_Attribute
445 {
446    ROUTE_XML_NONE,
447    ROUTE_XML_DISTANCE,
448    ROUTE_XML_DESCRIPTION,
449    ROUTE_XML_COORDINATES,
450    ROUTE_XML_LAST
451 } Route_Xml_Attibute;
452
453 struct _Name_Dump
454 {
455    int id;
456    char *address;
457    double lon;
458    double lat;
459 };
460
461 enum _Name_Xml_Attribute
462 {
463    NAME_XML_NONE,
464    NAME_XML_NAME,
465    NAME_XML_LON,
466    NAME_XML_LAT,
467    NAME_XML_LAST
468 } Name_Xml_Attibute;
469
470 enum _Zoom_Method
471 {
472    ZOOM_METHOD_NONE,
473    ZOOM_METHOD_IN,
474    ZOOM_METHOD_OUT,
475    ZOOM_METHOD_LAST
476 } Zoom_Mode;
477
478 static const char *widtype = NULL;
479
480 static const char SIG_CHANGED[] = "changed";
481 static const char SIG_CLICKED[] = "clicked";
482 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
483 static const char SIG_LOADED_DETAIL[] = "loaded,detail";
484 static const char SIG_LOAD_DETAIL[] = "load,detail";
485 static const char SIG_LONGPRESSED[] = "longpressed";
486 static const char SIG_PRESS[] = "press";
487 static const char SIG_SCROLL[] = "scroll";
488 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
489 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
490 static const char SIG_ZOOM_CHANGE[] = "zoom,change";
491 static const char SIG_ZOOM_START[] = "zoom,start";
492 static const char SIG_ZOOM_STOP[] = "zoom,stop";
493 static const char SIG_DOWNLOADED[] = "downloaded";
494 static const char SIG_ROUTE_LOAD[] = "route,load";
495 static const char SIG_ROUTE_LOADED[] = "route,loaded";
496 static const char SIG_NAME_LOAD[] = "name,load";
497 static const char SIG_NAME_LOADED[] = "name,loaded";
498 static const Evas_Smart_Cb_Description _signals[] = {
499        {SIG_CHANGED, ""},
500        {SIG_CLICKED, ""},
501        {SIG_CLICKED_DOUBLE, ""},
502        {SIG_LOADED_DETAIL, ""},
503        {SIG_LOAD_DETAIL, ""},
504        {SIG_LONGPRESSED, ""},
505        {SIG_PRESS, ""},
506        {SIG_SCROLL, ""},
507        {SIG_SCROLL_DRAG_START, ""},
508        {SIG_SCROLL_DRAG_STOP, ""},
509        {SIG_ZOOM_CHANGE, ""},
510        {SIG_ZOOM_START, ""},
511        {SIG_ZOOM_STOP, ""},
512        {SIG_DOWNLOADED, ""},
513        {SIG_ROUTE_LOAD, ""},
514        {SIG_ROUTE_LOADED, ""},
515        {SIG_NAME_LOAD, ""},
516        {SIG_NAME_LOADED, ""},
517        {NULL, NULL}
518 };
519
520 static void _pan_calculate(Evas_Object *obj);
521
522 static Eina_Bool _hold_timer_cb(void *data);
523 static Eina_Bool _wheel_timer_cb(void *data);
524 static void _rect_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
525 static void _del_hook(Evas_Object *obj);
526 static void _theme_hook(Evas_Object *obj);
527 static void _on_focus_hook(void *data, Evas_Object *obj);
528 static void _sizing_eval(Evas_Object *obj);
529 static void _calc_job(void *data);
530 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
531                              Evas_Callback_Type type, void *event_info);
532 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);
533 static void grid_clear(Evas_Object *obj, Grid *g);
534 static Grid *grid_create(Evas_Object *obj);
535 static void grid_load(Evas_Object *obj, Grid *g);
536
537
538 static void _group_object_create(Marker_Group *group);
539 static void _group_object_free(Marker_Group *group);
540 static void _group_open_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
541 static void _group_bringin_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
542 static void _group_bubble_create(Marker_Group *group);
543 static void _group_bubble_free(Marker_Group *group);
544 static void _group_bubble_place(Marker_Group *group);
545
546 static int _group_bubble_content_update(Marker_Group *group);
547 static void _group_bubble_content_free(Marker_Group *group);
548 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);
549 static void _bubble_sc_hits_changed_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
550
551 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
552 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
553 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
554
555 static void _mouse_multi_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
556 static void _mouse_multi_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
557 static void _mouse_multi_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
558
559 static void route_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh);
560
561 static int
562 get_multi_device(Evas_Object *obj)
563 {
564    Widget_Data *wd = elm_widget_data_get(obj);
565    Eina_List *l;
566    Event *ev;
567
568    EINA_LIST_FOREACH(wd->s_event_list, l, ev)
569      {
570         if (ev->device) return ev->device;
571      }
572    return 0;
573 }
574
575 static int
576 get_distance(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
577 {
578    int dx = x1 - x2;
579    int dy = y1 - y2;
580    return sqrt((dx * dx) + (dy * dy));
581 }
582
583 static Event *
584 create_event_object(void *data, Evas_Object *obj, int device)
585 {
586    Widget_Data *wd = elm_widget_data_get(data);
587    Event *ev = calloc(1, sizeof(Event));
588
589    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL);
590
591    ev->object = obj;
592    ev->device = device;
593    evas_object_geometry_get(obj, &ev->x, &ev->y, &ev->w, &ev->h);
594    wd->s_event_list = eina_list_append(wd->s_event_list, ev);
595    return ev;
596 }
597
598 static Event*
599 get_event_object(void *data, int device)
600 {
601    Widget_Data *wd = elm_widget_data_get(data);
602    Eina_List *l;
603    Event *ev;
604
605    EINA_LIST_FOREACH(wd->s_event_list, l, ev)
606      {
607         if (ev->device == device) break;
608         ev = NULL;
609      }
610    return ev;
611 }
612
613 static void
614 destroy_event_object(void *data, Event *ev)
615 {
616    Widget_Data *wd = elm_widget_data_get(data);
617    EINA_SAFETY_ON_NULL_RETURN(ev);
618    ev->pinch_dis = 0;
619    wd->s_event_list = eina_list_remove(wd->s_event_list, ev);
620    if (ev->hold_timer)
621      {
622         ecore_timer_del(ev->hold_timer);
623         ev->hold_timer = NULL;
624      }
625    free(ev);
626 }
627
628 static Eina_Bool
629 module_list_cb(Eina_Module *m, void *data)
630 {
631    ELM_CHECK_WIDTYPE(data, widtype) EINA_FALSE;
632    Widget_Data *wd = elm_widget_data_get(data);
633    Map_Sources_Tab *s;
634    ElmMapModuleSourceFunc source;
635    ElmMapModuleZoomMinFunc zoom_min;
636    ElmMapModuleZoomMaxFunc zoom_max;
637    ElmMapModuleUrlFunc url;
638    ElmMapModuleRouteSourceFunc route_source;
639    ElmMapModuleRouteUrlFunc route_url;
640    ElmMapModuleNameUrlFunc name_url;
641    ElmMapModuleGeoIntoCoordFunc geo_into_coord;
642    ElmMapModuleCoordIntoGeoFunc coord_into_geo;
643    const char *file;
644
645    if (!wd) return EINA_FALSE;
646
647    file = eina_module_file_get(m);
648    if (!eina_module_load(m))
649      {
650         ERR("could not load module \"%s\": %s", file, eina_error_msg_get(eina_error_get()));
651         return EINA_FALSE;
652      }
653
654    source = eina_module_symbol_get(m, "map_module_source_get");
655    zoom_min = eina_module_symbol_get(m, "map_module_zoom_min_get");
656    zoom_max = eina_module_symbol_get(m, "map_module_zoom_max_get");
657    url = eina_module_symbol_get(m, "map_module_url_get");
658    route_source = eina_module_symbol_get(m, "map_module_route_source_get");
659    route_url = eina_module_symbol_get(m, "map_module_route_url_get");
660    name_url = eina_module_symbol_get(m, "map_module_name_url_get");
661    geo_into_coord = eina_module_symbol_get(m, "map_module_geo_into_coord");
662    coord_into_geo = eina_module_symbol_get(m, "map_module_coord_into_geo");
663    if ((!source) || (!zoom_min) || (!zoom_max) || (!url) || (!route_source) || (!route_url) || (!name_url) || (!geo_into_coord) || (!coord_into_geo))
664      {
665         ERR("could not find map_module_source_get() in module \"%s\": %s", file, eina_error_msg_get(eina_error_get()));
666         eina_module_unload(m);
667         return EINA_FALSE;
668      }
669    s = calloc(1, sizeof(Map_Sources_Tab));
670    EINA_SAFETY_ON_NULL_RETURN_VAL(s, EINA_FALSE);
671    s->name = source();
672    s->zoom_min = zoom_min();
673    s->zoom_max = zoom_max();
674    s->url_cb = url;
675    s->route_source = route_source();
676    s->route_url_cb = route_url;
677    s->name_url_cb = name_url;
678    s->geo_into_coord = geo_into_coord;
679    s->coord_into_geo = coord_into_geo;
680    wd->map_sources_tab = eina_list_append(wd->map_sources_tab, s);
681
682    return EINA_TRUE;
683 }
684
685 static void
686 module_init(void *data)
687 {
688    ELM_CHECK_WIDTYPE(data, widtype);
689    Widget_Data *wd = elm_widget_data_get(data);
690
691    if (!wd) return;
692    wd->modules = eina_module_list_get(wd->modules, MODULES_PATH, 1, &module_list_cb, data);
693 }
694
695 static void
696 source_init(void *data)
697 {
698    ELM_CHECK_WIDTYPE(data, widtype);
699    Widget_Data *wd = elm_widget_data_get(data);
700    Map_Sources_Tab *s;
701    Eina_List *l;
702    int idx;
703
704    if (!wd) return;
705    for (idx = 0; idx < 4; idx++)
706      {
707         s = calloc(1, sizeof(Map_Sources_Tab));
708         EINA_SAFETY_ON_NULL_RETURN(s);
709         s->name = default_map_sources_tab[idx].name;
710         s->zoom_min = default_map_sources_tab[idx].zoom_min;
711         s->zoom_max = default_map_sources_tab[idx].zoom_max;
712         s->url_cb = default_map_sources_tab[idx].url_cb;
713         s->route_source = default_map_sources_tab[idx].route_source;
714         s->route_url_cb = default_map_sources_tab[idx].route_url_cb;
715         s->name_url_cb = default_map_sources_tab[idx].name_url_cb;
716         s->geo_into_coord = default_map_sources_tab[idx].geo_into_coord;
717         s->coord_into_geo = default_map_sources_tab[idx].coord_into_geo;
718         wd->map_sources_tab = eina_list_append(wd->map_sources_tab, s);
719      }
720    module_init(data);
721
722    int n = eina_list_count(wd->map_sources_tab);
723    wd->source_names = malloc(sizeof(char *) * (n + 1));
724    if (!wd->source_names)
725      {
726         ERR("init source names failed.");
727         return;
728      }
729    idx = 0;
730    EINA_LIST_FOREACH(wd->map_sources_tab, l, s)
731      {
732         wd->source_names[idx] = strdup(s->name);
733         INF("source : %s", wd->source_names[idx]);
734         idx++;
735      }
736    wd->source_names[idx] = NULL;
737 }
738
739 static void
740 obj_rotate_zoom(void *data, Evas_Object *obj)
741 {
742    ELM_CHECK_WIDTYPE(data, widtype);
743    Widget_Data *wd = elm_widget_data_get(data);
744    if ((!wd->pinch.cx) && (!wd->pinch.cy))
745      {
746         wd->pinch.cx = wd->rotate.cx;
747         wd->pinch.cy = wd->rotate.cy;
748      }
749
750    evas_map_util_points_populate_from_object_full(wd->map, obj, 0);
751    evas_map_util_zoom(wd->map, wd->pinch.level, wd->pinch.level, wd->pinch.cx, wd->pinch.cy);
752    evas_map_util_rotate(wd->map, wd->rotate.d, wd->rotate.cx, wd->rotate.cy);
753    evas_object_map_enable_set(obj, EINA_TRUE);
754    evas_object_map_set(obj, wd->map);
755 }
756
757 static void
758 route_place(Evas_Object *obj, Grid *g __UNUSED__, Evas_Coord px, Evas_Coord py, Evas_Coord ox __UNUSED__, Evas_Coord oy __UNUSED__, Evas_Coord ow, Evas_Coord oh)
759 {
760    ELM_CHECK_WIDTYPE(obj, widtype);
761    Widget_Data *wd = elm_widget_data_get(obj);
762    Eina_List *lr, *lp, *ln;
763    Route_Node *n;
764    Evas_Object *p;
765    Elm_Map_Route *r;
766    int nodes;
767    int x, y, rx, ry;
768    double a;
769
770    if (!wd) return;
771    Evas_Coord size = pow(2.0, wd->zoom)*wd->tsize;
772
773    EINA_LIST_FOREACH(wd->route, lr, r)
774      {
775         EINA_LIST_FOREACH(r->path, lp, p)
776           {
777              evas_object_polygon_points_clear(p);
778           }
779
780         evas_object_geometry_get(wd->rect, &rx, &ry, NULL, NULL);
781         nodes = eina_list_count(r->nodes);
782
783         EINA_LIST_FOREACH(r->nodes, ln, n)
784           {
785              if ((!wd->zoom) || ((n->idx) &&
786                  ((n->idx % (int)ceil((double)nodes/(double)size*100.0))))) continue;
787              if (r->inbound)
788                {
789                   elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
790                   if ((x >= px - ow) && (x <= (px + ow*2)) &&
791                       (y >= py - oh) && (y <= (py + oh*2)))
792                     {
793                        x = x - px + rx;
794                        y = y - py + ry;
795
796                        p = eina_list_nth(r->path, n->idx);
797                        a = (double)(y - r->y) / (double)(x - r->x);
798                        if ((abs(a) >= 1) || (r->x == x))
799                          {
800                             evas_object_polygon_point_add(p, r->x - 3, r->y);
801                             evas_object_polygon_point_add(p, r->x + 3, r->y);
802                             evas_object_polygon_point_add(p, x + 3, y);
803                             evas_object_polygon_point_add(p, x - 3, y);
804                          }
805                        else
806                          {
807                             evas_object_polygon_point_add(p, r->x, r->y - 3);
808                             evas_object_polygon_point_add(p, r->x, r->y + 3);
809                             evas_object_polygon_point_add(p, x, y + 3);
810                             evas_object_polygon_point_add(p, x, y - 3);
811                          }
812
813                        evas_object_color_set(p, r->color.r, r->color.g, r->color.b, r->color.a);
814                        evas_object_raise(p);
815                        obj_rotate_zoom(obj, p);
816                        evas_object_show(p);
817                        r->x = x;
818                        r->y = y;
819                     }
820                   else r->inbound = EINA_FALSE;
821                }
822              else
823                {
824                   elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
825                   if ((x >= px - ow) && (x <= (px + ow*2)) &&
826                       (y >= py - oh) && (y <= (py + oh*2)))
827                     {
828                        r->x = x - px + rx;
829                        r->y = y - py + ry;
830                        r->inbound = EINA_TRUE;
831                     }
832                   else r->inbound = EINA_FALSE;
833                }
834           }
835           r->inbound = EINA_FALSE;
836      }
837 }
838
839 static void
840 rect_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
841 {
842    ELM_CHECK_WIDTYPE(obj, widtype);
843    Widget_Data *wd = elm_widget_data_get(obj);
844    Evas_Coord ax, ay, gw, gh, hh, ww;
845
846    if (!wd) return;
847    evas_object_geometry_get(wd->rect, NULL, NULL, &ww, &hh);
848
849    ax = 0;
850    ay = 0;
851    gw = wd->size.w;
852    gh = wd->size.h;
853
854    if ((ww == gw) && (hh == gh)) return;
855
856    if (ow > gw) ax = (ow - gw) / 2;
857    if (oh > gh) ay = (oh - gh) / 2;
858    evas_object_move(wd->rect,
859                     ox + 0 - px + ax,
860                     oy + 0 - py + ay);
861    evas_object_resize(wd->rect, gw, gh);
862
863    if (wd->show.show)
864      {
865         wd->show.show = EINA_FALSE;
866         elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h);
867      }
868 }
869
870 static void
871 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)
872 {
873    ELM_CHECK_WIDTYPE(obj, widtype);
874    Widget_Data *wd = elm_widget_data_get(obj);
875    Evas_Coord ax, ay, gw, gh, tx, ty;
876    Eina_List *l, *markers;
877    Eina_Matrixsparse_Cell *cell;
878    Marker_Group *group;
879    int xx, yy, ww, hh;
880    char buf[PATH_MAX];
881    int y, x;
882    int g_xx, g_yy, g_hh, g_ww;
883
884    if (!wd) return;
885    if (g != eina_list_data_get(wd->grids)) return;
886
887    ax = 0;
888    ay = 0;
889    gw = wd->size.w;
890    gh = wd->size.h;
891    if (ow > gw) ax = (ow - gw) / 2;
892    if (oh > gh) ay = (oh - gh) / 2;
893
894    if (wd->zoom != wd->marker_zoom)
895      {
896         EINA_LIST_FREE(wd->cells_displayed, cell)
897           {
898              EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
899                {
900                   if (group->obj) _group_object_free(group);
901                }
902           }
903      }
904    wd->marker_zoom = wd->zoom;
905
906    if ((wd->paused_markers)
907        && ((wd->size.nw != wd->size.w) || (wd->size.nh != wd->size.h)) )
908      return;
909
910    g_xx = wd->pan_x / wd->tsize;
911    if (g_xx < 0) g_xx = 0;
912    g_yy = wd->pan_y / wd->tsize;
913    if (g_yy < 0) g_yy = 0;
914    g_ww = (ow / wd->tsize) + 1;
915    if (g_xx + g_ww >= g->gw) g_ww = g->gw - g_xx - 1;
916    g_hh = (oh / wd->tsize) + 1;
917    if (g_yy + g_hh >= g->gh) g_hh = g->gh - g_yy - 1;
918
919    //hide groups no more displayed
920    EINA_LIST_FREE(wd->cells_displayed, cell)
921      {
922         eina_matrixsparse_cell_position_get(cell, (unsigned long *)&y, (unsigned long *)&x);
923         if ((y < g_yy) || (y > g_yy + g_hh) || (x < g_xx) || (x > g_xx + g_ww))
924           {
925              EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
926                {
927                   if (group->obj) _group_object_free(group);
928                }
929           }
930      }
931
932    if (!wd->marker_zoom)
933      {
934         g_ww = 0;
935         g_hh = 0;
936      }
937
938    for (y = g_yy; y <= g_yy + g_hh; y++)
939      {
940         for (x = g_xx; x <= g_xx + g_ww; x++)
941           {
942              if (!wd->markers[wd->zoom]) continue;
943              eina_matrixsparse_cell_idx_get(wd->markers[wd->zoom], y, x, &cell);
944              if (!cell) continue;
945              wd->cells_displayed = eina_list_append(wd->cells_displayed, cell);
946              markers = eina_matrixsparse_cell_data_get(cell);
947              EINA_LIST_FOREACH(markers, l, group)
948                {
949                   if (!group->markers) continue;
950                   if (group->clas->zoom_displayed > wd->zoom) continue;
951
952                   xx = group->x;
953                   yy = group->y;
954                   ww = group->w;
955                   hh = group->h;
956
957                   if (eina_list_count(group->markers) == 1)
958                     {
959                        Elm_Map_Marker *m = eina_list_data_get(group->markers);
960                        ww = m->clas->priv.edje_w;
961                        hh = m->clas->priv.edje_h;
962                     }
963
964                   if (ww <= 0) ww = 1;
965                   if (hh <= 0) hh = 1;
966
967                   if ((gw != g->w) && (g->w > 0))
968                     {
969                        tx = xx;
970                        xx = ((long long )gw * xx) / g->w;
971                        ww = (((long long)gw * (tx + ww)) / g->w) - xx;
972                     }
973                   if ((gh != g->h) && (g->h > 0))
974                     {
975                        ty = yy;
976                        yy = ((long long)gh * yy) / g->h;
977                        hh = (((long long)gh * (ty + hh)) / g->h) - yy;
978                     }
979
980                   if ((!group->clas->hide)
981                       && (xx-px+ax+ox >= ox) && (xx-px+ax+ox<= ox+ow)
982                       && (yy-py+ay+oy >= oy) && (yy-py+ay+oy<= oy+oh))
983                     {
984                        if (!group->obj) _group_object_create(group);
985
986                        if (group->update_nbelems)
987                          {
988                             group->update_nbelems = EINA_FALSE;
989                             if (eina_list_count(group->markers) > 1)
990                               {
991                                  snprintf(buf, sizeof(buf), "%d", eina_list_count(group->markers));
992                                  edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", buf);
993                               }
994                             else
995                               edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", "");
996                          }
997                        evas_object_move(group->obj,
998                                         xx - px + ax + ox - ww/2,
999                                         yy - py + ay + oy - hh/2);
1000                        if ((!wd->paused_markers) || (group->update_resize))
1001                          {
1002                             group->update_resize = EINA_FALSE;
1003                             evas_object_resize(group->obj, ww, hh);
1004                             obj_rotate_zoom(obj, group->obj);
1005                          }
1006                        if (group->update_raise)
1007                          {
1008                             group->update_raise = EINA_FALSE;
1009                             evas_object_raise(group->obj);
1010                             obj_rotate_zoom(obj, group->obj);
1011                             evas_object_show(group->obj);
1012                          }
1013                        if (group->bubble) _group_bubble_place(group);
1014                     }
1015                   else if (group->obj)
1016                     {
1017                        _group_object_free(group);
1018                     }
1019                }
1020           }
1021      }
1022 }
1023
1024 static void
1025 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)
1026 {
1027    ELM_CHECK_WIDTYPE(obj, widtype);
1028    Widget_Data *wd = elm_widget_data_get(obj);
1029    Evas_Coord ax, ay, gw, gh, tx, ty;
1030    int xx, yy, ww, hh;
1031
1032    if (!wd) return;
1033    ax = 0;
1034    ay = 0;
1035    gw = wd->size.w;
1036    gh = wd->size.h;
1037    if (ow > gw) ax = (ow - gw) / 2;
1038    if (oh > gh) ay = (oh - gh) / 2;
1039
1040    Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
1041    Eina_Matrixsparse_Cell *cell;
1042
1043    EINA_ITERATOR_FOREACH(it, cell)
1044      {
1045         Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
1046
1047         xx = gi->out.x;
1048         yy = gi->out.y;
1049         ww = gi->out.w;
1050         hh = gi->out.h;
1051         if ((gw != g->w) && (g->w > 0))
1052           {
1053              tx = xx;
1054              xx = ((long long )gw * xx) / g->w;
1055              ww = (((long long)gw * (tx + ww)) / g->w) - xx;
1056           }
1057         if ((gh != g->h) && (g->h > 0))
1058           {
1059              ty = yy;
1060              yy = ((long long)gh * yy) / g->h;
1061              hh = (((long long)gh * (ty + hh)) / g->h) - yy;
1062           }
1063         evas_object_move(gi->img,
1064                          xx - px + ax + ox,
1065                          yy - py + ay + oy);
1066
1067         evas_object_resize(gi->img, ww, hh);
1068
1069         obj_rotate_zoom(obj, gi->img);
1070         /*evas_object_move(gi->txt,
1071                            xx - px + ax + ox,
1072                            yy - py + ay + oy);
1073
1074           evas_object_resize(gi->txt, ww, hh);
1075          */
1076      }
1077    eina_iterator_free(it);
1078 }
1079
1080 static void
1081 grid_clear(Evas_Object *obj, Grid *g)
1082 {
1083    ELM_CHECK_WIDTYPE(obj, widtype);
1084    Widget_Data *wd = elm_widget_data_get(obj);
1085    char buf[PATH_MAX];
1086
1087    if (!wd) return;
1088    if (!g->grid) return;
1089
1090    Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
1091    Eina_Matrixsparse_Cell *cell;
1092
1093    snprintf(buf, sizeof(buf), DEST_DIR_ZOOM_PATH, wd->id, g->zoom);
1094    ecore_file_recursive_rm(buf);
1095
1096    EINA_ITERATOR_FOREACH(it, cell)
1097      {
1098         Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
1099         evas_object_del(gi->img);
1100         //evas_object_del(gi->txt);
1101
1102         if (gi->want)
1103           {
1104              gi->want = EINA_FALSE;
1105              wd->preload_num--;
1106              if (!wd->preload_num)
1107                {
1108                   edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1109                                           "elm,state,busy,stop", "elm");
1110                   evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL, NULL);
1111                }
1112           }
1113
1114         if (gi->job)
1115           {
1116              DBG("DOWNLOAD abort %s", gi->file);
1117              ecore_file_download_abort(gi->job);
1118              ecore_file_remove(gi->file);
1119              gi->job = NULL;
1120              wd->try_num--;
1121           }
1122         if (gi->file)
1123           eina_stringshare_del(gi->file);
1124
1125         free(gi);
1126      }
1127    eina_matrixsparse_free(g->grid);
1128    eina_iterator_free(it);
1129    g->grid = NULL;
1130    g->gw = 0;
1131    g->gh = 0;
1132 }
1133
1134 static void
1135 _tile_update(Grid_Item *gi)
1136 {
1137    gi->want = EINA_FALSE;
1138    gi->download = EINA_FALSE;
1139    evas_object_image_file_set(gi->img, gi->file, NULL);
1140    if (evas_object_image_load_error_get(gi->img) != EVAS_LOAD_ERROR_NONE)
1141      ecore_file_remove(gi->file);
1142
1143    obj_rotate_zoom(gi->wd->obj, gi->img);
1144    evas_object_show(gi->img);
1145
1146    //evas_object_text_text_set(gi->txt, gi->file);
1147    //evas_object_show(gi->txt);
1148
1149    gi->have = EINA_TRUE;
1150    gi->wd->preload_num--;
1151    if (!gi->wd->preload_num)
1152      {
1153         edje_object_signal_emit(elm_smart_scroller_edje_object_get(gi->wd->scr),
1154                                 "elm,state,busy,stop", "elm");
1155         evas_object_smart_callback_call(gi->wd->obj, SIG_LOADED_DETAIL, NULL);
1156      }
1157 }
1158
1159
1160 static void
1161 _tile_downloaded(void *data, const char *file __UNUSED__, int status)
1162 {
1163    Grid_Item *gi = data;
1164
1165    gi->download = EINA_FALSE;
1166    gi->job = NULL;
1167
1168    DBG("DOWNLOAD done %s", gi->file);
1169    if ((gi->want) && (!status)) _tile_update(gi);
1170
1171    if (status)
1172      {
1173         DBG("Download failed %s (%d) ", gi->file, status);
1174         ecore_file_remove(gi->file);
1175      }
1176    else
1177      gi->wd->finish_num++;
1178
1179    evas_object_smart_callback_call(gi->wd->obj, SIG_DOWNLOADED, NULL);
1180 }
1181
1182 static Grid *
1183 grid_create(Evas_Object *obj)
1184 {
1185    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1186    Widget_Data *wd = elm_widget_data_get(obj);
1187    Map_Sources_Tab *s  = NULL, *ss;
1188    Eina_List *l;
1189    Grid *g;
1190
1191    if (!wd) return NULL;
1192    g = calloc(1, sizeof(Grid));
1193
1194    g->zoom = wd->zoom;
1195    g->tsize = wd->tsize;
1196    g->wd = wd;
1197
1198    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
1199      {
1200         if (!strcmp(ss->name, wd->source_name))
1201           {
1202              s = ss;
1203              break;
1204           }
1205      }
1206    if (!s) return NULL;
1207    if (g->zoom > s->zoom_max) return NULL;
1208    if (g->zoom < s->zoom_min) return NULL;
1209
1210    int size =  pow(2.0, wd->zoom);
1211    g->gw = size;
1212    g->gh = size;
1213
1214    g->w = g->tsize * g->gw;
1215    g->h = g->tsize * g->gh;
1216
1217    g->grid = eina_matrixsparse_new(g->gh, g->gw, NULL, NULL);
1218
1219    return g;
1220 }
1221
1222 static void
1223 grid_load(Evas_Object *obj, Grid *g)
1224 {
1225    ELM_CHECK_WIDTYPE(obj, widtype);
1226    Widget_Data *wd = elm_widget_data_get(obj);
1227    int x, y;
1228    int size;
1229    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, tx, ty, gw, gh, xx, yy, ww, hh;
1230    Eina_Iterator *it;
1231    Eina_Matrixsparse_Cell *cell;
1232    Grid_Item *gi;
1233    Map_Sources_Tab *s = NULL, *ss;
1234    Eina_List *l;
1235
1236    if (!wd) return;
1237    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
1238      {
1239         if (!strcmp(ss->name, wd->source_name))
1240           {
1241              s = ss;
1242              break;
1243           }
1244      }
1245    if (!s) return;
1246
1247    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
1248    evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
1249
1250    gw = wd->size.w;
1251    gh = wd->size.h;
1252
1253    if ((gw <= 0) || (gh <= 0)) return;
1254
1255    size = g->tsize;
1256    if ((gw != g->w) && (g->w > 0))
1257      size = ((long long)gw * size) / g->w;
1258    if (size < (g->tsize / 2)) return; // else we will load to much tiles
1259
1260    it = eina_matrixsparse_iterator_new(g->grid);
1261
1262    EINA_ITERATOR_FOREACH(it, cell)
1263      {
1264         gi = eina_matrixsparse_cell_data_get(cell);
1265
1266         xx = gi->out.x;
1267         yy = gi->out.y;
1268         ww = gi->out.w;
1269         hh = gi->out.h;
1270
1271         if ((gw != g->w) && (g->w > 0))
1272           {
1273              tx = xx;
1274              xx = ((long long )gw * xx) / g->w;
1275              ww = (((long long)gw * (tx + ww)) / g->w) - xx;
1276           }
1277         if ((gh != g->h) && (g->h > 0))
1278           {
1279              ty = yy;
1280              yy = ((long long)gh * yy) / g->h;
1281              hh = (((long long)gh * (ty + hh)) / g->h) - yy;
1282           }
1283
1284         if (!ELM_RECTS_INTERSECT(xx - wd->pan_x + ox,
1285                                  yy  - wd->pan_y + oy,
1286                                  ww, hh,
1287                                  cvx, cvy, cvw, cvh))
1288           {
1289              if (gi->want)
1290                {
1291                   evas_object_hide(gi->img);
1292                   //evas_object_hide(gi->txt);
1293                   evas_object_image_file_set(gi->img, NULL, NULL);
1294                   gi->want = EINA_FALSE;
1295                   gi->have = EINA_FALSE;
1296
1297                   if (gi->job)
1298                     {
1299                        DBG("DOWNLOAD abort %s", gi->file);
1300                        ecore_file_download_abort(gi->job);
1301                        ecore_file_remove(gi->file);
1302                        gi->job = NULL;
1303                        wd->try_num--;
1304                     }
1305                   gi->download = EINA_FALSE;
1306                   wd->preload_num--;
1307                   if (!wd->preload_num)
1308                     {
1309                        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1310                                                "elm,state,busy,stop", "elm");
1311                        evas_object_smart_callback_call(obj, SIG_LOADED_DETAIL,
1312                                                        NULL);
1313                     }
1314
1315                }
1316              else if (gi->have)
1317                {
1318                   evas_object_hide(gi->img);
1319                   //evas_object_hide(gi->txt);
1320                   evas_object_image_preload(gi->img, 1);
1321                   evas_object_image_file_set(gi->img, NULL, NULL);
1322                   gi->have = EINA_FALSE;
1323                   gi->want = EINA_FALSE;
1324                }
1325           }
1326      }
1327    eina_iterator_free(it);
1328
1329    xx = wd->pan_x / size - 2;
1330    if (xx < 0) xx = 0;
1331
1332    yy = wd->pan_y / size - 2;
1333    if (yy < 0) yy = 0;
1334
1335    ww = ow / size + 4;
1336    if (xx + ww >= g->gw) ww = g->gw - xx - 1;
1337
1338    hh = oh / size + 4;
1339    if (yy + hh >= g->gh) hh = g->gh - yy - 1;
1340
1341    for (y = yy; y <= yy + hh; y++)
1342      {
1343         for (x = xx; x <= xx + ww; x++)
1344           {
1345              gi = eina_matrixsparse_data_idx_get(g->grid, y, x);
1346
1347              if ((!gi) && (g != eina_list_data_get(wd->grids)))
1348                continue;
1349
1350              if (!gi)
1351                {
1352                   gi = calloc(1, sizeof(Grid_Item));
1353                   gi->src.x = x * g->tsize;
1354                   gi->src.y = y * g->tsize;
1355                   gi->src.w = g->tsize;
1356                   gi->src.h = g->tsize;
1357
1358                   gi->out.x = gi->src.x;
1359                   gi->out.y = gi->src.y;
1360                   gi->out.w = gi->src.w;
1361                   gi->out.h = gi->src.h;
1362
1363                   gi->wd = wd;
1364
1365                   gi->img = evas_object_image_add(evas_object_evas_get(obj));
1366                   evas_object_image_scale_hint_set
1367                      (gi->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
1368                   evas_object_image_filled_set(gi->img, 1);
1369
1370                   evas_object_smart_member_add(gi->img, wd->pan_smart);
1371                   elm_widget_sub_object_add(obj, gi->img);
1372                   evas_object_pass_events_set(gi->img, EINA_TRUE);
1373                   evas_object_stack_below(gi->img, wd->sep_maps_markers);
1374
1375 /*                gi->txt = evas_object_text_add(evas_object_evas_get(obj));
1376                   evas_object_text_font_set(gi->txt, "Vera", 12);
1377                   evas_object_color_set(gi->txt, 100, 100, 100, 255);
1378                   evas_object_smart_member_add(gi->txt,
1379                                                wd->pan_smart);
1380                   elm_widget_sub_object_add(obj, gi->txt);
1381                   evas_object_pass_events_set(gi->txt, EINA_TRUE);
1382 */
1383                   eina_matrixsparse_data_idx_set(g->grid, y, x, gi);
1384                }
1385
1386              if ((!gi->have) && (!gi->download))
1387                {
1388                   char buf[PATH_MAX], buf2[PATH_MAX];
1389                   char *source;
1390
1391                   gi->want = EINA_TRUE;
1392
1393                   snprintf(buf, sizeof(buf), DEST_DIR_PATH, wd->id, g->zoom, x);
1394                   if (!ecore_file_exists(buf))
1395                     ecore_file_mkpath(buf);
1396
1397                   snprintf(buf2, sizeof(buf2), DEST_FILE_PATH, buf, y);
1398
1399                   source = s->url_cb(obj, x, y, g->zoom);
1400                   if ((!source) || (strlen(source)==0)) continue;
1401
1402                   eina_stringshare_replace(&gi->file, buf2);
1403
1404                   if ((ecore_file_exists(buf2)) || (g == eina_list_data_get(wd->grids)))
1405                     {
1406                        gi->download = EINA_TRUE;
1407                        wd->preload_num++;
1408                        if (wd->preload_num == 1)
1409                          {
1410                             edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
1411                                                     "elm,state,busy,start", "elm");
1412                             evas_object_smart_callback_call(obj,
1413                                                             SIG_LOAD_DETAIL,
1414                                                             NULL);
1415                          }
1416
1417                        if (ecore_file_exists(buf2))
1418                          _tile_update(gi);
1419                        else
1420                          {
1421                             DBG("DOWNLOAD %s \t in %s", source, buf2);
1422                             ecore_file_download_full(source, buf2, _tile_downloaded, NULL, gi, &(gi->job), wd->ua);
1423                             if (!gi->job)
1424                               DBG("Can't start to download %s", buf);
1425                             else
1426                               wd->try_num++;
1427                          }
1428                     }
1429                   if (source) free(source);
1430                }
1431              else if (gi->have)
1432                {
1433                   obj_rotate_zoom(obj, gi->img);
1434                   evas_object_show(gi->img);
1435                }
1436           }
1437      }
1438 }
1439
1440 static void
1441 grid_clearall(Evas_Object *obj)
1442 {
1443    ELM_CHECK_WIDTYPE(obj, widtype);
1444    Widget_Data *wd = elm_widget_data_get(obj);
1445    Grid *g;
1446
1447    if (!wd) return;
1448    EINA_LIST_FREE(wd->grids, g)
1449      {
1450         grid_clear(obj, g);
1451         free(g);
1452      }
1453 }
1454
1455 static void
1456 _smooth_update(Evas_Object *obj)
1457 {
1458    ELM_CHECK_WIDTYPE(obj, widtype);
1459    Widget_Data *wd = elm_widget_data_get(obj);
1460    Eina_List *l;
1461    Grid *g;
1462
1463    if (!wd) return;
1464    EINA_LIST_FOREACH(wd->grids, l, g)
1465      {
1466         Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
1467         Eina_Matrixsparse_Cell *cell;
1468
1469         EINA_ITERATOR_FOREACH(it, cell)
1470           {
1471              Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
1472              evas_object_image_smooth_scale_set(gi->img, (!wd->nosmooth));
1473           }
1474         eina_iterator_free(it);
1475      }
1476 }
1477
1478 static Eina_Bool
1479 _scr_timeout(void *data)
1480 {
1481    ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
1482    Widget_Data *wd = elm_widget_data_get(data);
1483
1484    if (!wd) return ECORE_CALLBACK_CANCEL;
1485    wd->nosmooth--;
1486    if (!wd->nosmooth) _smooth_update(data);
1487    wd->scr_timer = NULL;
1488    return ECORE_CALLBACK_CANCEL;
1489 }
1490
1491 static void
1492 _scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1493 {
1494    ELM_CHECK_WIDTYPE(data, widtype);
1495    Widget_Data *wd = elm_widget_data_get(data);
1496
1497    if (!wd) return;
1498    if (!wd->scr_timer)
1499      {
1500         wd->nosmooth++;
1501         if (wd->nosmooth == 1) _smooth_update(data);
1502      }
1503    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
1504    wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
1505 }
1506
1507 static void
1508 zoom_do(Evas_Object *obj)
1509 {
1510    ELM_CHECK_WIDTYPE(obj, widtype);
1511    Widget_Data *wd = elm_widget_data_get(obj);
1512    Evas_Coord xx, yy, ow, oh;
1513
1514    if (!wd) return;
1515    wd->size.w = wd->size.nw;
1516    wd->size.h = wd->size.nh;
1517
1518    elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
1519
1520    if (wd->center_on.enabled)
1521      {
1522         elm_map_utils_convert_geo_into_coord(obj, wd->center_on.lon, wd->center_on.lat, wd->size.w, &xx, &yy);
1523         xx -= ow / 2;
1524         yy -= oh / 2;
1525      }
1526    else
1527      {
1528         xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
1529         yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
1530      }
1531
1532
1533    if (xx < 0) xx = 0;
1534    else if (xx > (wd->size.w - ow)) xx = wd->size.w - ow;
1535    if (yy < 0) yy = 0;
1536    else if (yy > (wd->size.h - oh)) yy = wd->size.h - oh;
1537
1538    wd->show.show = EINA_TRUE;
1539    wd->show.x = xx;
1540    wd->show.y = yy;
1541    wd->show.w = ow;
1542    wd->show.h = oh;
1543
1544    if (wd->calc_job) ecore_job_del(wd->calc_job);
1545    wd->calc_job = ecore_job_add(_calc_job, wd);
1546 }
1547
1548 static Eina_Bool
1549 _zoom_timeout(void *data)
1550 {
1551    ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
1552    Widget_Data *wd = elm_widget_data_get(data);
1553
1554    if (!wd) return ECORE_CALLBACK_CANCEL;
1555    wd->zoom_timer = NULL;
1556    wd->pinch.level = 1.0;
1557    zoom_do(data);
1558    evas_object_smart_callback_call(data, SIG_ZOOM_STOP, NULL);
1559    return ECORE_CALLBACK_CANCEL;
1560 }
1561
1562 static Eina_Bool
1563 _zoom_anim(void *data)
1564 {
1565    ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
1566    Evas_Object *obj = data;
1567    Widget_Data *wd = elm_widget_data_get(obj);
1568
1569    if (!wd) return ECORE_CALLBACK_CANCEL;
1570    if (wd->zoom_method == ZOOM_METHOD_IN) wd->t += 0.1 ;
1571    else if (wd->zoom_method == ZOOM_METHOD_OUT) wd->t -= 0.05;
1572    else
1573      {
1574         wd->zoom_animator = NULL;
1575         zoom_do(obj);
1576         evas_object_smart_callback_call(data, SIG_ZOOM_STOP, NULL);
1577         return ECORE_CALLBACK_CANCEL;
1578      }
1579
1580    if (wd->t >= 2.0)
1581      {
1582         wd->zoom_animator = NULL;
1583         wd->pinch.level = 2.0;
1584         if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
1585         wd->zoom_timer = ecore_timer_add(0.35, _zoom_timeout, obj);
1586         return ECORE_CALLBACK_CANCEL;
1587      }
1588    else if (wd->t <= 0.5)
1589      {
1590         wd->zoom_animator = NULL;
1591         wd->pinch.level = 0.5;
1592         if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
1593         wd->zoom_timer = ecore_timer_add(1.35, _zoom_timeout, obj);
1594         return ECORE_CALLBACK_CANCEL;
1595      }
1596    else if (wd->t != 1.0)
1597      {
1598         Evas_Coord x, y, w, h;
1599         float half_w, half_h;
1600         evas_object_geometry_get(data, &x, &y, &w, &h);
1601         half_w = (float)w * 0.5;
1602         half_h = (float)h * 0.5;
1603         wd->pinch.cx = x + half_w;
1604         wd->pinch.cy = y + half_h;
1605         wd->pinch.level = wd->t;
1606         if (wd->calc_job) ecore_job_del(wd->calc_job);
1607         wd->calc_job = ecore_job_add(_calc_job, wd);
1608      }
1609    return ECORE_CALLBACK_RENEW;
1610 }
1611
1612 static Eina_Bool
1613 _long_press(void *data)
1614 {
1615    ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
1616    Widget_Data *wd = elm_widget_data_get(data);
1617
1618    if (!wd) return ECORE_CALLBACK_CANCEL;
1619    wd->long_timer = NULL;
1620    evas_object_smart_callback_call(data, SIG_LONGPRESSED, &wd->ev);
1621    return ECORE_CALLBACK_CANCEL;
1622 }
1623
1624 static void
1625 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
1626 {
1627    ELM_CHECK_WIDTYPE(data, widtype);
1628    Widget_Data *wd = elm_widget_data_get(data);
1629    Evas_Event_Mouse_Down *ev = event_info;
1630    Event *ev0;
1631
1632    if (!wd) return;
1633    ev0 = get_event_object(data, 0);
1634    if (ev0) return;
1635    ev0 = create_event_object(data, obj, 0);
1636    if (!ev0) return;
1637
1638    ev0->hold_timer = NULL;
1639    ev0->prev.x = ev->output.x;
1640    ev0->prev.y = ev->output.y;
1641
1642    if (ev->button != 1) return;
1643    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
1644    else wd->on_hold = EINA_FALSE;
1645    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
1646      evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, ev);
1647    else
1648      evas_object_smart_callback_call(data, SIG_PRESS, ev);
1649    if (wd->long_timer) ecore_timer_del(wd->long_timer);
1650    wd->ev.output.x = ev->output.x;
1651    wd->ev.output.y = ev->output.y;
1652    wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data);
1653 }
1654
1655 static void
1656 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1657 {
1658    Evas_Event_Mouse_Move *move = event_info;
1659    Event *ev0;
1660
1661    ev0 = get_event_object(data, 0);
1662    if (!ev0) return;
1663    ev0->prev.x = move->cur.output.x;
1664    ev0->prev.y = move->cur.output.y;
1665 }
1666
1667 static void
1668 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1669 {
1670    ELM_CHECK_WIDTYPE(data, widtype);
1671    Widget_Data *wd = elm_widget_data_get(data);
1672
1673    if (!wd) return;
1674    Evas_Event_Mouse_Up *ev = event_info;
1675    int mdevice;
1676    Event *ev0;
1677    Event *ev1;
1678
1679    ev0 = get_event_object(data, 0);
1680    if (ev0)
1681      {
1682         mdevice = get_multi_device(data);
1683         if (mdevice == 0)
1684           {
1685              if (ev0->hold_timer)
1686                {
1687                   ecore_timer_del(ev0->hold_timer);
1688                   ev0->hold_timer = NULL;
1689                }
1690              elm_smart_scroller_hold_set(wd->scr, 0);
1691              elm_smart_scroller_freeze_set(wd->scr, 0);
1692           }
1693         else
1694           {
1695              ev1 = get_event_object(data, mdevice);
1696              if (ev1)
1697                ev1->hold_timer = ecore_timer_add(0.35, _hold_timer_cb, ev1);
1698           }
1699         destroy_event_object(data, ev0);
1700      }
1701
1702    if (ev->button != 1) return;
1703    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
1704    else wd->on_hold = EINA_FALSE;
1705    if (wd->long_timer)
1706      {
1707         ecore_timer_del(wd->long_timer);
1708         wd->long_timer = NULL;
1709      }
1710    if (!wd->on_hold) evas_object_smart_callback_call(data, SIG_CLICKED, ev);
1711    wd->on_hold = EINA_FALSE;
1712 }
1713
1714 static void
1715 _mouse_multi_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info)
1716 {
1717    ELM_CHECK_WIDTYPE(data, widtype);
1718    Widget_Data *wd = elm_widget_data_get(data);
1719    Event *ev;
1720    Evas_Event_Multi_Down *down = event_info;
1721
1722    elm_smart_scroller_hold_set(wd->scr, 1);
1723    elm_smart_scroller_freeze_set(wd->scr, 1);
1724
1725    ev = create_event_object(data, obj, down->device);
1726    if (!ev)
1727      {
1728         DBG("Failed : create_event_object");
1729         goto done;
1730      }
1731    wd->multi_count++;
1732
1733    ev->hold_timer = NULL;
1734    ev->start.x = ev->prev.x = down->output.x;
1735    ev->start.y = ev->prev.y = down->output.y;
1736    ev->pinch_start_dis = 0;
1737    wd->pinch.level = 1.0;
1738    wd->pinch.diff = 1.0;
1739
1740 done:
1741    if (wd->long_timer)
1742      {
1743         ecore_timer_del(wd->long_timer);
1744         wd->long_timer = NULL;
1745      }
1746    return;
1747 }
1748
1749 static void
1750 _mouse_multi_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1751 {
1752    ELM_CHECK_WIDTYPE(data, widtype);
1753    Widget_Data *wd = elm_widget_data_get(data);
1754    Evas_Event_Multi_Move *move = event_info;
1755    Map_Sources_Tab *s = NULL, *ss;
1756    Eina_List *l;
1757    int dis_new;
1758    double t, tt, a, a_diff;
1759    Event *ev0;
1760    Event *ev;
1761
1762    if (!wd) return;
1763    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
1764      {
1765         if (!strcmp(ss->name, wd->source_name))
1766           {
1767              s = ss;
1768              break;
1769           }
1770      }
1771    if (!s) return;
1772
1773    ev = get_event_object(data, move->device);
1774    if (!ev) return;
1775
1776    ev0 = get_event_object(data, 0);
1777    if (!ev0) return;
1778
1779    if (wd->multi_count >= 1)
1780      {
1781         Evas_Coord x, y, w, h;
1782         float half_w, half_h;
1783
1784         evas_object_geometry_get(data, &x, &y, &w, &h);
1785         half_w = (float)w * 0.5;
1786         half_h = (float)h * 0.5;
1787         dis_new = get_distance(ev0->prev.x, ev0->prev.y, ev->prev.x, ev->prev.y);
1788
1789         if (!ev->pinch_start_dis) ev->pinch_start_dis = dis_new;
1790         else
1791           {
1792              ev->pinch_dis = dis_new;
1793              tt = wd->pinch.diff;
1794              wd->pinch.diff = (double)(ev->pinch_dis - ev->pinch_start_dis);
1795              t = (wd->pinch.diff * 0.01) + 1.0;
1796              if ((!wd->zoom) || ((wd->zoom + (int)t - 1) <= s->zoom_min) ||
1797                  ((wd->zoom + (int)t - 1) >= s->zoom_max) ||
1798                  (t > PINCH_ZOOM_MAX) || (t < PINCH_ZOOM_MIN))
1799                {
1800                   wd->pinch.diff = tt;
1801                   goto do_nothing;
1802                }
1803              else
1804                {
1805                   wd->pinch.level = (wd->pinch.diff * 0.01) + 1.0;
1806                   wd->pinch.cx = x + half_w;
1807                   wd->pinch.cy = y + half_h;
1808                }
1809
1810              a = (double)(ev->prev.y - ev0->prev.y) / (double)(ev->prev.x - ev0->prev.x);
1811              if (!wd->rotate.a) wd->rotate.a = a;
1812              else
1813                {
1814                   a_diff = wd->rotate.a - a;
1815                   if (a_diff > 0) wd->rotate.d -= 1.0;
1816                   else if (a_diff < 0) wd->rotate.d += 1.0;
1817                   wd->rotate.a = a;
1818                   wd->rotate.cx = x + half_w;
1819                   wd->rotate.cy = y + half_h;
1820                }
1821
1822              if (wd->calc_job) ecore_job_del(wd->calc_job);
1823              wd->calc_job = ecore_job_add(_calc_job, wd);
1824           }
1825      }
1826 do_nothing:
1827    ev->prev.x = move->cur.output.x;
1828    ev->prev.y = move->cur.output.y;
1829 }
1830
1831 static void
1832 _mouse_multi_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1833 {
1834    ELM_CHECK_WIDTYPE(data, widtype);
1835    Widget_Data *wd = elm_widget_data_get(data);
1836    Evas_Event_Multi_Up *up = event_info;
1837    Event *ev0;
1838    Event *ev;
1839    Eina_Bool tp;
1840    double t = 0.0;
1841
1842    wd->multi_count--;
1843    if (wd->calc_job) ecore_job_del(wd->calc_job);
1844    if (wd->zoom_animator)
1845      {
1846         ecore_animator_del(wd->zoom_animator);
1847         wd->zoom_animator = NULL;
1848      }
1849    tp = wd->paused;
1850    wd->paused = EINA_TRUE;
1851    if (wd->pinch.diff >= 0.0) t = wd->pinch.diff * 0.01;
1852    else if (wd->pinch.diff < 0.0) t = -1.0 / ((wd->pinch.diff * 0.01) + 1.0);
1853    elm_map_zoom_set(data, wd->zoom + (int)ceil(t));
1854    wd->pinch.level = 1.0;
1855    wd->paused = tp;
1856    wd->rotate.a = 0.0;
1857
1858    ev = get_event_object(data, up->device);
1859    if (!ev)
1860      {
1861         DBG("Cannot get multi device");
1862         return;
1863      }
1864
1865    ev0 = get_event_object(data, 0);
1866    if (ev0)
1867      ev0->hold_timer = ecore_timer_add(0.35, _hold_timer_cb, ev0);
1868    else
1869      {
1870         if (ev->hold_timer)
1871           {
1872              ecore_timer_del(ev->hold_timer);
1873              ev->hold_timer = NULL;
1874           }
1875      }
1876    destroy_event_object(data, ev);
1877 }
1878
1879 static void
1880 _mouse_wheel_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1881 {
1882    ELM_CHECK_WIDTYPE(data, widtype);
1883    Widget_Data *wd = elm_widget_data_get(data);
1884    Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel*) event_info;
1885    Evas_Coord x, y, w, h;
1886    float half_w, half_h;
1887
1888    if (!wd) return;
1889    evas_object_geometry_get(data, &x, &y, &w, &h);
1890    half_w = (float)w * 0.5;
1891    half_h = (float)h * 0.5;
1892
1893    if (!wd->wheel_zoom) wd->wheel_zoom = 1.0;
1894    if (ev->z > 0)
1895      {
1896         wd->zoom_method = ZOOM_METHOD_OUT;
1897         wd->wheel_zoom -= 0.05;
1898         if (wd->wheel_zoom <= PINCH_ZOOM_MIN) wd->wheel_zoom = PINCH_ZOOM_MIN;
1899      }
1900    else
1901      {
1902         wd->zoom_method = ZOOM_METHOD_IN;
1903         wd->wheel_zoom += 0.2;
1904         if (wd->wheel_zoom >= PINCH_ZOOM_MAX) wd->wheel_zoom = PINCH_ZOOM_MAX;
1905      }
1906
1907    if (!wd->paused)
1908      {
1909    wd->pinch.level = wd->wheel_zoom;
1910    wd->pinch.cx = x + half_w;
1911    wd->pinch.cy = y + half_h;
1912    if (wd->calc_job) ecore_job_del(wd->calc_job);
1913    wd->calc_job = ecore_job_add(_calc_job, wd);
1914      }
1915
1916    if (wd->wheel_timer) ecore_timer_del(wd->wheel_timer);
1917    wd->wheel_timer = ecore_timer_add(0.35, _wheel_timer_cb, data);
1918 }
1919
1920
1921 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL;
1922
1923 static Eina_Bool
1924 _hold_timer_cb(void *data)
1925 {
1926    Event *ev0 = data;
1927
1928    ev0->hold_timer = NULL;
1929    return ECORE_CALLBACK_CANCEL;
1930 }
1931
1932 static Eina_Bool
1933 _wheel_timer_cb(void *data)
1934 {
1935    ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
1936    Widget_Data *wd = elm_widget_data_get(data);
1937    int zoom;
1938
1939    if (!wd)
1940      {
1941         wd->wheel_timer = NULL;
1942         return ECORE_CALLBACK_CANCEL;
1943      }
1944    if (wd->zoom_method == ZOOM_METHOD_IN) zoom = (int)ceil(wd->wheel_zoom - 1.0);
1945    else if (wd->zoom_method == ZOOM_METHOD_OUT) zoom = (int)floor((-1.0 / wd->wheel_zoom) + 1.0);
1946    else
1947      {
1948         wd->wheel_timer = NULL;
1949         return ECORE_CALLBACK_CANCEL;
1950      }
1951    wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
1952    elm_map_zoom_set(data, wd->zoom + zoom);
1953    wd->wheel_zoom = 0.0;
1954    wd->wheel_timer = NULL;
1955    return ECORE_CALLBACK_CANCEL;
1956 }
1957
1958 static void
1959 _rect_resize_cb(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1960 {
1961    ELM_CHECK_WIDTYPE(data, widtype);
1962    Widget_Data *wd = elm_widget_data_get(data);
1963    int x, y, w, h;
1964
1965    evas_object_geometry_get(wd->rect, &x, &y, &w, &h);
1966    evas_object_geometry_get(wd->pan_smart, &x, &y, &w, &h);
1967    evas_object_resize(wd->rect, w, h);
1968    evas_object_move(wd->rect, x, y);
1969 }
1970
1971 static void
1972 _del_hook(Evas_Object *obj)
1973 {
1974    ELM_CHECK_WIDTYPE(obj, widtype);
1975    Widget_Data *wd = elm_widget_data_get(obj);
1976    Elm_Map_Group_Class *group_clas;
1977    Elm_Map_Marker_Class *marker_clas;
1978    Eina_List *l;
1979    Event *ev;
1980    Evas_Object *p;
1981    Route_Node *n;
1982    Route_Waypoint *w;
1983    Ecore_Event_Handler *h;
1984    Elm_Map_Route *r;
1985    Elm_Map_Name *na;
1986
1987    if (!wd) return;
1988    EINA_LIST_FREE(wd->groups_clas, group_clas)
1989      {
1990         if (group_clas->style)
1991           eina_stringshare_del(group_clas->style);
1992         free(group_clas);
1993      }
1994
1995    EINA_LIST_FREE(wd->markers_clas, marker_clas)
1996      {
1997         if (marker_clas->style)
1998           eina_stringshare_del(marker_clas->style);
1999         free(marker_clas);
2000      }
2001
2002    EINA_LIST_FOREACH(wd->s_event_list, l, ev)
2003      {
2004         destroy_event_object(obj, ev);
2005      }
2006
2007    EINA_LIST_FOREACH(wd->route, l, r)
2008      {
2009         EINA_LIST_FREE(r->path, p)
2010           {
2011              evas_object_del(p);
2012           }
2013
2014         EINA_LIST_FREE(r->waypoint, w)
2015           {
2016              if (w->point) eina_stringshare_del(w->point);
2017              free(w);
2018           }
2019
2020         EINA_LIST_FREE(r->nodes, n)
2021           {
2022              if (n->pos.address) eina_stringshare_del(n->pos.address);
2023              free(n);
2024           }
2025
2026         EINA_LIST_FREE(r->handlers, h)
2027           {
2028              ecore_event_handler_del(h);
2029           }
2030
2031         if (r->con_url) ecore_con_url_free(r->con_url);
2032         if (r->info.nodes) eina_stringshare_del(r->info.nodes);
2033         if (r->info.waypoints) eina_stringshare_del(r->info.waypoints);
2034      }
2035
2036    EINA_LIST_FREE(wd->names, na)
2037      {
2038         if (na->address) free(na->address);
2039         if (na->handler) ecore_event_handler_del(na->handler);
2040         if (na->ud.fname)
2041           {
2042              ecore_file_remove(na->ud.fname);
2043              free(na->ud.fname);
2044              na->ud.fname = NULL;
2045           }
2046      }
2047
2048    if (wd->map) evas_map_free(wd->map);
2049    if (wd->source_names) free(wd->source_names);
2050    if (wd->calc_job) ecore_job_del(wd->calc_job);
2051    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
2052    if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
2053    if (wd->long_timer) ecore_timer_del(wd->long_timer);
2054    if (wd->user_agent) eina_stringshare_del(wd->user_agent);
2055    if (wd->ua) eina_hash_free(wd->ua);
2056
2057    free(wd);
2058 }
2059
2060 static void
2061 _del_pre_hook(Evas_Object *obj)
2062 {
2063    ELM_CHECK_WIDTYPE(obj, widtype);
2064    Widget_Data *wd = elm_widget_data_get(obj);
2065    Marker_Group *group;
2066    Elm_Map_Marker *marker;
2067    int i;
2068    Eina_Bool free_marker = EINA_TRUE;
2069    Eina_List *l;
2070
2071    if (!wd) return;
2072    grid_clearall(obj);
2073    for (i = 0; i < ZOOM_MAX + 1; i++)
2074      {
2075         if (!wd->markers[i]) continue;
2076         Eina_Iterator *it = eina_matrixsparse_iterator_new(wd->markers[i]);
2077         Eina_Matrixsparse_Cell *cell;
2078
2079         EINA_ITERATOR_FOREACH(it, cell)
2080           {
2081              l =  eina_matrixsparse_cell_data_get(cell);
2082              EINA_LIST_FREE(l, group)
2083                {
2084                   EINA_LIST_FREE(group->markers, marker)
2085                     {
2086                        evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2087                                                            _bubble_sc_hits_changed_cb, group);
2088                        if (free_marker) free(marker);
2089                     }
2090                   free(group);
2091                }
2092              free_marker = EINA_FALSE;
2093           }
2094         eina_iterator_free(it);
2095         eina_matrixsparse_free(wd->markers[i]);
2096      }
2097
2098    evas_object_del(wd->sep_maps_markers);
2099    evas_object_del(wd->pan_smart);
2100    wd->pan_smart = NULL;
2101 }
2102
2103 static void
2104 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
2105 {
2106    ELM_CHECK_WIDTYPE(obj, widtype);
2107    Widget_Data *wd = elm_widget_data_get(obj);
2108
2109    if (!wd) return;
2110    if (elm_widget_focus_get(obj))
2111      {
2112         edje_object_signal_emit(wd->obj, "elm,action,focus", "elm");
2113         evas_object_focus_set(wd->obj, EINA_TRUE);
2114      }
2115    else
2116      {
2117         edje_object_signal_emit(wd->obj, "elm,action,unfocus", "elm");
2118         evas_object_focus_set(wd->obj, EINA_FALSE);
2119      }
2120 }
2121
2122 static void
2123 _theme_hook(Evas_Object *obj)
2124 {
2125    ELM_CHECK_WIDTYPE(obj, widtype);
2126    Widget_Data *wd = elm_widget_data_get(obj);
2127
2128    if (!wd) return;
2129    elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", elm_widget_style_get(obj));
2130    //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
2131    _sizing_eval(obj);
2132 }
2133
2134 static void
2135 _sizing_eval(Evas_Object *obj)
2136 {
2137    ELM_CHECK_WIDTYPE(obj, widtype);
2138    Widget_Data *wd = elm_widget_data_get(obj);
2139    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
2140
2141    if (!wd) return;
2142    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
2143    evas_object_size_hint_min_set(obj, minw, minh);
2144    evas_object_size_hint_max_set(obj, maxw, maxh);
2145 }
2146
2147 static void
2148 _calc_job(void *data)
2149 {
2150    Widget_Data *wd = data;
2151    Evas_Coord minw, minh;
2152
2153    if (!wd) return;
2154    minw = wd->size.w;
2155    minh = wd->size.h;
2156    if (wd->resized)
2157      {
2158         wd->resized = EINA_FALSE;
2159         if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
2160           {
2161              double tz = wd->zoom;
2162              wd->zoom = 0.0;
2163              elm_map_zoom_set(wd->obj, tz);
2164           }
2165      }
2166    if ((minw != wd->minw) || (minh != wd->minh))
2167      {
2168         wd->minw = minw;
2169         wd->minh = minh;
2170         evas_object_smart_callback_call(wd->pan_smart, SIG_CHANGED, NULL);
2171         _sizing_eval(wd->obj);
2172      }
2173    wd->calc_job = NULL;
2174    evas_object_smart_changed(wd->pan_smart);
2175 }
2176
2177 static void
2178 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2179 {
2180    Pan *sd = evas_object_smart_data_get(obj);
2181    if (!sd) return;
2182    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
2183    sd->wd->pan_x = x;
2184    sd->wd->pan_y = y;
2185    evas_object_smart_changed(obj);
2186 }
2187
2188 static void
2189 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
2190 {
2191    Pan *sd = evas_object_smart_data_get(obj);
2192    if (!sd) return;
2193    if (x) *x = sd->wd->pan_x;
2194    if (y) *y = sd->wd->pan_y;
2195 }
2196
2197 static void
2198 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
2199 {
2200    Pan *sd = evas_object_smart_data_get(obj);
2201    Evas_Coord ow, oh;
2202    if (!sd) return;
2203    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2204    ow = sd->wd->minw - ow;
2205    if (ow < 0) ow = 0;
2206    oh = sd->wd->minh - oh;
2207    if (oh < 0) oh = 0;
2208    if (x) *x = ow;
2209    if (y) *y = oh;
2210 }
2211
2212 static void
2213 _pan_min_get(Evas_Object *obj __UNUSED__, Evas_Coord *x, Evas_Coord *y)
2214 {
2215    if (x) *x = 0;
2216    if (y) *y = 0;
2217 }
2218
2219 static void
2220 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
2221 {
2222    Pan *sd = evas_object_smart_data_get(obj);
2223    if (!sd) return;
2224    if (w) *w = sd->wd->minw;
2225    if (h) *h = sd->wd->minh;
2226 }
2227
2228 static void
2229 _pan_add(Evas_Object *obj)
2230 {
2231    Pan *sd;
2232    Evas_Object_Smart_Clipped_Data *cd;
2233    _pan_sc.add(obj);
2234    cd = evas_object_smart_data_get(obj);
2235    if (!cd) return;
2236    sd = calloc(1, sizeof(Pan));
2237    if (!sd) return;
2238    sd->__clipped_data = *cd;
2239    free(cd);
2240    evas_object_smart_data_set(obj, sd);
2241 }
2242
2243 static void
2244 _pan_del(Evas_Object *obj)
2245 {
2246    Pan *sd = evas_object_smart_data_get(obj);
2247    if (!sd) return;
2248    _pan_sc.del(obj);
2249 }
2250
2251 static void
2252 _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2253 {
2254    Pan *sd = evas_object_smart_data_get(obj);
2255    Evas_Coord ow, oh;
2256    if (!sd) return;
2257    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2258    if ((ow == w) && (oh == h)) return;
2259    sd->wd->resized = EINA_TRUE;
2260    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2261    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2262 }
2263
2264 static void
2265 _pan_calculate(Evas_Object *obj)
2266 {
2267    Pan *sd = evas_object_smart_data_get(obj);
2268    Evas_Coord ox, oy, ow, oh;
2269    Eina_List *l;
2270    Grid *g;
2271    if (!sd) return;
2272    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
2273    rect_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
2274    EINA_LIST_FOREACH(sd->wd->grids, l, g)
2275      {
2276         grid_load(sd->wd->obj, g);
2277         grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
2278         marker_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
2279         if (!sd->wd->zoom_animator) route_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
2280      }
2281 }
2282
2283 static void
2284 _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
2285 {
2286    Pan *sd = evas_object_smart_data_get(obj);
2287    if (!sd) return;
2288    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2289    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2290 }
2291
2292 static void
2293 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2294 {
2295    ELM_CHECK_WIDTYPE(obj, widtype);
2296    Widget_Data *wd = elm_widget_data_get(obj);
2297
2298    if (!wd) return;
2299    elm_smart_scroller_hold_set(wd->scr, 1);
2300 }
2301
2302 static void
2303 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2304 {
2305    ELM_CHECK_WIDTYPE(obj, widtype);
2306    Widget_Data *wd = elm_widget_data_get(obj);
2307
2308    if (!wd) return;
2309    elm_smart_scroller_hold_set(wd->scr, 0);
2310 }
2311
2312 static void
2313 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2314 {
2315    ELM_CHECK_WIDTYPE(obj, widtype);
2316    Widget_Data *wd = elm_widget_data_get(obj);
2317
2318    if (!wd) return;
2319    elm_smart_scroller_freeze_set(wd->scr, 1);
2320 }
2321
2322 static void
2323 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2324 {
2325    ELM_CHECK_WIDTYPE(obj, widtype);
2326    Widget_Data *wd = elm_widget_data_get(obj);
2327
2328    if (!wd) return;
2329    elm_smart_scroller_freeze_set(wd->scr, 0);
2330 }
2331
2332 static void
2333 _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2334 {
2335    evas_object_smart_callback_call(data, "scroll,anim,start", NULL);
2336 }
2337
2338 static void
2339 _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2340 {
2341    evas_object_smart_callback_call(data, "scroll,anim,stop", NULL);
2342 }
2343
2344 static void
2345 _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2346 {
2347    Widget_Data *wd = elm_widget_data_get(data);
2348    wd->center_on.enabled = EINA_FALSE;
2349    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
2350 }
2351
2352 static void
2353 _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2354 {
2355    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
2356 }
2357
2358 static void
2359 _scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2360 {
2361    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
2362 }
2363
2364
2365 static void
2366 _group_object_create(Marker_Group *group)
2367 {
2368    const char *style = "radio";
2369    Evas_Object *icon = NULL;
2370
2371    if (group->obj) return;
2372    if ((!group->clas->priv.objs_notused) || (eina_list_count(group->markers) == 1))
2373      {
2374         //set icon and style
2375         if (eina_list_count(group->markers) == 1)
2376           {
2377              Elm_Map_Marker *m = eina_list_data_get(group->markers);
2378              if (m->clas->style)
2379                style = m->clas->style;
2380
2381              if (m->clas->func.icon_get)
2382                icon = m->clas->func.icon_get(group->wd->obj, m, m->data);
2383
2384              group->delete_object = EINA_TRUE;
2385           }
2386         else
2387           {
2388              if (group->clas->style)
2389                style = group->clas->style;
2390
2391              if (group->clas->func.icon_get)
2392                icon = group->clas->func.icon_get(group->wd->obj, group->clas->data);
2393
2394              group->delete_object = EINA_FALSE;
2395           }
2396
2397         group->obj = elm_layout_add(group->wd->obj);
2398         elm_layout_theme_set(group->obj, "map/marker", style, elm_widget_style_get(group->wd->obj));
2399
2400         if (icon) elm_layout_content_set(group->obj, "elm.icon", icon);
2401
2402         evas_object_smart_member_add(group->obj, group->wd->pan_smart);
2403         elm_widget_sub_object_add(group->wd->obj, group->obj);
2404         evas_object_stack_above(group->obj, group->wd->sep_maps_markers);
2405
2406         if (!group->delete_object)
2407           group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
2408      }
2409    else
2410      {
2411         group->delete_object = EINA_FALSE;
2412
2413         group->obj = eina_list_data_get(group->clas->priv.objs_notused);
2414         group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
2415         group->clas->priv.objs_notused = eina_list_remove(group->clas->priv.objs_notused, group->obj);
2416         evas_object_show(group->obj);
2417      }
2418
2419    edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb, group);
2420    edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb, group);
2421
2422    group->update_nbelems = EINA_TRUE;
2423    group->update_resize = EINA_TRUE;
2424    group->update_raise = EINA_TRUE;
2425
2426    if (group->open) _group_bubble_create(group);
2427 }
2428
2429 static void
2430 _group_object_free(Marker_Group *group)
2431 {
2432    if (!group->obj) return;
2433    if (!group->delete_object)
2434      {
2435         group->clas->priv.objs_notused = eina_list_append(group->clas->priv.objs_notused, group->obj);
2436         group->clas->priv.objs_used = eina_list_remove(group->clas->priv.objs_used, group->obj);
2437         evas_object_hide(group->obj);
2438
2439         edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb);
2440         edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb);
2441      }
2442    else
2443      evas_object_del(group->obj);
2444
2445    group->obj = NULL;
2446    _group_bubble_free(group);
2447 }
2448
2449 static void
2450 _group_bubble_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2451 {
2452    Marker_Group *group = data;
2453
2454    if (!evas_object_above_get(group->rect)) return;
2455    evas_object_raise(group->bubble);
2456    evas_object_raise(group->sc);
2457    evas_object_raise(group->rect);
2458 }
2459
2460 static void
2461 _group_bubble_create(Marker_Group *group)
2462 {
2463    if (group->bubble) return;
2464
2465    group->wd->opened_bubbles = eina_list_append(group->wd->opened_bubbles, group);
2466    group->bubble = edje_object_add(evas_object_evas_get(group->obj));
2467    _elm_theme_object_set(group->wd->obj, group->bubble, "map", "marker_bubble",
2468                          elm_widget_style_get(group->wd->obj));
2469    evas_object_smart_member_add(group->bubble,
2470                                 group->wd->obj);
2471    elm_widget_sub_object_add(group->wd->obj, group->bubble);
2472
2473    _group_bubble_content_free(group);
2474    if (!_group_bubble_content_update(group))
2475      {
2476         //no content, we can delete the bubble
2477         _group_bubble_free(group);
2478         return;
2479      }
2480
2481    group->rect = evas_object_rectangle_add(evas_object_evas_get(group->obj));
2482    evas_object_color_set(group->rect, 0, 0, 0, 0);
2483    evas_object_repeat_events_set(group->rect, EINA_TRUE);
2484    evas_object_smart_member_add(group->rect, group->wd->obj);
2485    elm_widget_sub_object_add(group->wd->obj, group->rect);
2486
2487    evas_object_event_callback_add(group->rect, EVAS_CALLBACK_MOUSE_UP, _group_bubble_mouse_up_cb, group);
2488
2489    _group_bubble_place(group);
2490 }
2491
2492 static void _bubble_sc_hits_changed_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2493 {
2494    _group_bubble_place(data);
2495 }
2496
2497 static int
2498 _group_bubble_content_update(Marker_Group *group)
2499 {
2500    Eina_List *l;
2501    Elm_Map_Marker *marker;
2502    int i = 0;
2503
2504    if (!group->bubble) return 1;
2505
2506    if (!group->sc)
2507      {
2508         group->sc = elm_scroller_add(group->bubble);
2509         elm_widget_style_set(group->sc, "map_bubble");
2510         elm_scroller_content_min_limit(group->sc, EINA_FALSE, EINA_TRUE);
2511         elm_scroller_policy_set(group->sc, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
2512         elm_scroller_bounce_set(group->sc, _elm_config->thumbscroll_bounce_enable, EINA_FALSE);
2513         edje_object_part_swallow(group->bubble, "elm.swallow.content", group->sc);
2514         evas_object_show(group->sc);
2515         evas_object_smart_member_add(group->sc,
2516                                      group->wd->obj);
2517         elm_widget_sub_object_add(group->wd->obj, group->sc);
2518
2519         group->bx = elm_box_add(group->bubble);
2520         evas_object_size_hint_align_set(group->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
2521         evas_object_size_hint_weight_set(group->bx, 0.5, 0.5);
2522         elm_box_horizontal_set(group->bx, EINA_TRUE);
2523         evas_object_show(group->bx);
2524
2525         elm_scroller_content_set(group->sc, group->bx);
2526
2527         evas_object_event_callback_add(group->sc, EVAS_CALLBACK_RESIZE,
2528                                        _bubble_sc_hits_changed_cb, group);
2529      }
2530
2531    EINA_LIST_FOREACH(group->markers, l, marker)
2532      {
2533         if (i >= group->wd->markers_max_num) break;
2534         if ((!marker->content) && (marker->clas->func.get))
2535           marker->content = marker->clas->func.get(group->wd->obj, marker, marker->data);
2536         else if (marker->content)
2537           elm_box_unpack(group->bx, marker->content);
2538         if (marker->content)
2539           {
2540              elm_box_pack_end(group->bx, marker->content);
2541              i++;
2542           }
2543      }
2544    return i;
2545 }
2546
2547 static void
2548 _group_bubble_content_free(Marker_Group *group)
2549 {
2550    Eina_List *l;
2551    Elm_Map_Marker *marker;
2552
2553    if (!group->sc) return;
2554    EINA_LIST_FOREACH(group->markers, l, marker)
2555      {
2556         if ((marker->content) && (marker->clas->func.del))
2557           marker->clas->func.del(group->wd->obj, marker, marker->data, marker->content);
2558         else if (marker->content)
2559           evas_object_del(marker->content);
2560         marker->content = NULL;
2561      }
2562    evas_object_del(group->sc);
2563    group->sc = NULL;
2564 }
2565
2566 static void
2567 _group_bubble_free(Marker_Group *group)
2568 {
2569    if (!group->bubble) return;
2570    group->wd->opened_bubbles = eina_list_remove(group->wd->opened_bubbles, group);
2571    evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2572                                        _bubble_sc_hits_changed_cb, group);
2573    evas_object_del(group->bubble);
2574    evas_object_del(group->rect);
2575    group->bubble = NULL;
2576    _group_bubble_content_free(group);
2577 }
2578
2579 static void
2580 _group_bubble_place(Marker_Group *group)
2581 {
2582    Evas_Coord x, y, w;
2583    Evas_Coord xx, yy, ww, hh;
2584    const char *s;
2585
2586    if ((!group->bubble) || (!group->obj)) return;
2587
2588    evas_object_geometry_get(group->obj, &x, &y, &w, NULL);
2589    edje_object_size_min_calc(group->bubble, NULL, &hh);
2590
2591    s = edje_object_data_get(group->bubble, "size_w");
2592    if (s) ww = atoi(s);
2593    else ww = 0;
2594    xx = x + w / 2 - ww / 2;
2595    yy = y-hh;
2596
2597    evas_object_move(group->bubble, xx, yy);
2598    evas_object_resize(group->bubble, ww, hh);
2599    obj_rotate_zoom(group->wd, group->bubble);
2600    evas_object_show(group->bubble);
2601
2602    evas_object_move(group->rect, xx, yy);
2603    evas_object_resize(group->rect, ww, hh);
2604    obj_rotate_zoom(group->wd, group->rect);
2605    evas_object_show(group->rect);
2606 }
2607
2608 static void
2609 _group_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
2610 {
2611    Marker_Group *group = data;
2612    Elm_Map_Marker *marker = eina_list_data_get(group->markers);
2613    if (!marker) return;
2614    group->bringin = EINA_TRUE;
2615    elm_map_geo_region_bring_in(group->wd->obj, marker->longitude, marker->latitude);
2616 }
2617
2618 static void
2619 _group_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
2620 {
2621    Marker_Group *group = data;
2622
2623    if (group->bringin)
2624      {
2625         group->bringin = EINA_FALSE;
2626         return;
2627      }
2628
2629    if (group->bubble)
2630      {
2631         group->open = EINA_FALSE;
2632         _group_bubble_free(group);
2633         return;
2634      }
2635    group->open = EINA_TRUE;
2636    _group_bubble_create(group);
2637 }
2638
2639 static Eina_Bool
2640 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
2641 {
2642    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2643    Widget_Data *wd = elm_widget_data_get(obj);
2644    int zoom;
2645    Evas_Coord x = 0;
2646    Evas_Coord y = 0;
2647    Evas_Coord step_x = 0;
2648    Evas_Coord step_y = 0;
2649    Evas_Coord v_w = 0;
2650    Evas_Coord v_h = 0;
2651    Evas_Coord page_x = 0;
2652    Evas_Coord page_y = 0;
2653
2654    if (!wd) return EINA_FALSE;
2655    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
2656    Evas_Event_Key_Down *ev = event_info;
2657    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
2658
2659    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
2660    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
2661    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
2662    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
2663
2664    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
2665      {
2666         x -= step_x;
2667      }
2668    else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
2669      {
2670         x += step_x;
2671      }
2672    else if ((!strcmp(ev->keyname, "Up"))  || (!strcmp(ev->keyname, "KP_Up")))
2673      {
2674         y -= step_y;
2675      }
2676    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
2677      {
2678         y += step_y;
2679      }
2680    else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior")))
2681      {
2682         if (page_y < 0)
2683           y -= -(page_y * v_h) / 100;
2684         else
2685           y -= page_y;
2686      }
2687    else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
2688      {
2689         if (page_y < 0)
2690           y += -(page_y * v_h) / 100;
2691         else
2692           y += page_y;
2693      }
2694    else if (!strcmp(ev->keyname, "KP_Add"))
2695      {
2696         zoom = elm_map_zoom_get(obj) + 1;
2697         elm_map_zoom_mode_set(obj, ELM_MAP_ZOOM_MODE_MANUAL);
2698         elm_map_zoom_set(obj, zoom);
2699         return EINA_TRUE;
2700      }
2701    else if (!strcmp(ev->keyname, "KP_Subtract"))
2702      {
2703         zoom = elm_map_zoom_get(obj) - 1;
2704         elm_map_zoom_mode_set(obj, ELM_MAP_ZOOM_MODE_MANUAL);
2705         elm_map_zoom_set(obj, zoom);
2706         return EINA_TRUE;
2707      }
2708    else return EINA_FALSE;
2709
2710    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2711    elm_smart_scroller_child_pos_set(wd->scr, x, y);
2712
2713    return EINA_TRUE;
2714 }
2715
2716 static Eina_Bool
2717 cb_dump_name_attrs(void *data, const char *key, const char *value)
2718 {
2719    Name_Dump *dump = (Name_Dump*)data;
2720    if (!dump) return EINA_FALSE;
2721
2722    if (!strncmp(key, NOMINATIM_ATTR_LON, sizeof(NOMINATIM_ATTR_LON))) dump->lon = atof(value);
2723    else if (!strncmp(key, NOMINATIM_ATTR_LAT, sizeof(NOMINATIM_ATTR_LAT))) dump->lat = atof(value);
2724
2725    return EINA_TRUE;
2726 }
2727
2728
2729 static Eina_Bool
2730 cb_route_dump(void *data, Eina_Simple_XML_Type type, const char *value, unsigned offset __UNUSED__, unsigned length)
2731 {
2732    Route_Dump *dump = data;
2733    if (!dump) return EINA_FALSE;
2734
2735    switch (type)
2736      {
2737       case EINA_SIMPLE_XML_OPEN:
2738       case EINA_SIMPLE_XML_OPEN_EMPTY:
2739         {
2740            const char *attrs;
2741
2742            attrs = eina_simple_xml_tag_attributes_find(value, length);
2743            if (!attrs)
2744              {
2745                 if (!strncmp(value, YOURS_DISTANCE, length)) dump->id = ROUTE_XML_DISTANCE;
2746                 else if (!strncmp(value, YOURS_DESCRIPTION, length)) dump->id = ROUTE_XML_DESCRIPTION;
2747                 else if (!strncmp(value, YOURS_COORDINATES, length)) dump->id = ROUTE_XML_COORDINATES;
2748                 else dump->id = ROUTE_XML_NONE;
2749              }
2750          }
2751         break;
2752       case EINA_SIMPLE_XML_DATA:
2753         {
2754            char *buf = malloc(length);
2755            if (!buf) return EINA_FALSE;
2756            snprintf(buf, length, "%s", value);
2757            if (dump->id == ROUTE_XML_DISTANCE) dump->distance = atof(buf);
2758            else if (!(dump->description) && (dump->id == ROUTE_XML_DESCRIPTION)) dump->description = strdup(buf);
2759            else if (dump->id == ROUTE_XML_COORDINATES) dump->coordinates = strdup(buf);
2760            free(buf);
2761         }
2762         break;
2763       default:
2764         break;
2765      }
2766
2767    return EINA_TRUE;
2768 }
2769
2770 static Eina_Bool
2771 cb_name_dump(void *data, Eina_Simple_XML_Type type, const char *value, unsigned offset __UNUSED__, unsigned length)
2772 {
2773    Name_Dump *dump = data;
2774    if (!dump) return EINA_FALSE;
2775
2776    switch (type)
2777      {
2778       case EINA_SIMPLE_XML_OPEN:
2779       case EINA_SIMPLE_XML_OPEN_EMPTY:
2780         {
2781            const char *attrs;
2782            attrs = eina_simple_xml_tag_attributes_find(value, length);
2783            if (attrs)
2784              {
2785                 if (!strncmp(value, NOMINATIM_RESULT, sizeof(NOMINATIM_RESULT) - 1)) dump->id = NAME_XML_NAME;
2786                 else dump->id = NAME_XML_NONE;
2787
2788                 eina_simple_xml_attributes_parse
2789                   (attrs, length - (attrs - value), cb_dump_name_attrs, dump);
2790              }
2791         }
2792         break;
2793       case EINA_SIMPLE_XML_DATA:
2794         {
2795            char *buf = malloc(length + 1);
2796            if (!buf) return EINA_FALSE;
2797            snprintf(buf, length + 1, "%s", value);
2798            if (dump->id == NAME_XML_NAME) dump->address = strdup(buf);
2799            free(buf);
2800         }
2801         break;
2802       default:
2803         break;
2804      }
2805
2806    return EINA_TRUE;
2807 }
2808
2809 static void
2810 _parse_kml(void *data)
2811 {
2812    Elm_Map_Route *r = (Elm_Map_Route*)data;
2813    if (!r && !r->ud.fname) return;
2814
2815    FILE *f;
2816    char **str;
2817    unsigned int ele, idx;
2818    double lon, lat;
2819    Evas_Object *path;
2820
2821    Route_Dump dump = {0, r->ud.fname, 0.0, NULL, NULL};
2822
2823    f = fopen(r->ud.fname, "rb");
2824    if (f)
2825      {
2826         long sz;
2827
2828         fseek(f, 0, SEEK_END);
2829         sz = ftell(f);
2830         if (sz > 0)
2831           {
2832              char *buf;
2833
2834              fseek(f, 0, SEEK_SET);
2835              buf = malloc(sz);
2836              if (buf)
2837                {
2838                   if (fread(buf, 1, sz, f))
2839                     {
2840                        eina_simple_xml_parse(buf, sz, EINA_TRUE, cb_route_dump, &dump);
2841                        free(buf);
2842                     }
2843                }
2844           }
2845         fclose(f);
2846
2847         if (dump.distance) r->info.distance = dump.distance;
2848         if (dump.description)
2849           {
2850              eina_stringshare_replace(&r->info.waypoints, dump.description);
2851              str = eina_str_split_full(dump.description, "\n", 0, &ele);
2852              r->info.waypoint_count = ele;
2853              for (idx = 0 ; idx < ele ; idx++)
2854                {
2855                   Route_Waypoint *wp = ELM_NEW(Route_Waypoint);
2856                   if (wp)
2857                     {
2858                        wp->wd = r->wd;
2859                        wp->point = eina_stringshare_add(str[idx]);
2860                        DBG("%s", str[idx]);
2861                        r->waypoint = eina_list_append(r->waypoint, wp);
2862                     }
2863                }
2864              if (str && str[0])
2865                {
2866                   free(str[0]);
2867                   free(str);
2868                }
2869           }
2870         else WRN("description is not found !");
2871
2872         if (dump.coordinates)
2873           {
2874              eina_stringshare_replace(&r->info.nodes, dump.coordinates);
2875              str = eina_str_split_full(dump.coordinates, "\n", 0, &ele);
2876              r->info.node_count = ele;
2877              for (idx = 0 ; idx < ele ; idx++)
2878                {
2879                   sscanf(str[idx], "%lf,%lf", &lon, &lat);
2880                   Route_Node *n = ELM_NEW(Route_Node);
2881                   if (n)
2882                     {
2883                        n->wd = r->wd;
2884                        n->pos.lon = lon;
2885                        n->pos.lat = lat;
2886                        n->idx = idx;
2887                        DBG("%lf:%lf", lon, lat);
2888                        n->pos.address = NULL;
2889                        r->nodes = eina_list_append(r->nodes, n);
2890
2891                        path = evas_object_polygon_add(evas_object_evas_get(r->wd->obj));
2892                        evas_object_smart_member_add(path, r->wd->pan_smart);
2893                        r->path = eina_list_append(r->path, path);
2894                     }
2895                }
2896              if (str && str[0])
2897                {
2898                   free(str[0]);
2899                   free(str);
2900                }
2901           }
2902      }
2903 }
2904
2905 static void
2906 _parse_name(void *data)
2907 {
2908    Elm_Map_Name *n = (Elm_Map_Name*)data;
2909    if (!n && !n->ud.fname) return;
2910
2911    FILE *f;
2912
2913    Name_Dump dump = {0, NULL, 0.0, 0.0};
2914
2915    f = fopen(n->ud.fname, "rb");
2916    if (f)
2917      {
2918         long sz;
2919
2920         fseek(f, 0, SEEK_END);
2921         sz = ftell(f);
2922         if (sz > 0)
2923           {
2924              char *buf;
2925
2926              fseek(f, 0, SEEK_SET);
2927              buf = malloc(sz);
2928              if (buf)
2929                {
2930                   if (fread(buf, 1, sz, f))
2931                     {
2932                        eina_simple_xml_parse(buf, sz, EINA_TRUE, cb_name_dump, &dump);
2933                        free(buf);
2934                     }
2935                }
2936           }
2937         fclose(f);
2938
2939         if (dump.address)
2940           {
2941              INF("[%lf : %lf] ADDRESS : %s", n->lon, n->lat, dump.address);
2942              n->address = strdup(dump.address);
2943           }
2944         n->lon = dump.lon;
2945         n->lat = dump.lat;
2946      }
2947 }
2948
2949 static Eina_Bool
2950 _route_complete_cb(void *data, int ev_type __UNUSED__, void *event)
2951 {
2952    Ecore_Con_Event_Url_Complete *ev = event;
2953    Elm_Map_Route *r = (Elm_Map_Route*)data;
2954    Widget_Data *wd = r->wd;
2955
2956    if ((!r) || (!ev)) return EINA_TRUE;
2957    Elm_Map_Route *rr = ecore_con_url_data_get(r->con_url);
2958    ecore_con_url_data_set(r->con_url, NULL);
2959    if (r!=rr) return EINA_TRUE;
2960
2961    if (r->ud.fd) fclose(r->ud.fd);
2962    _parse_kml(r);
2963
2964    if (wd->grids)
2965      {
2966         Evas_Coord ox, oy, ow, oh;
2967         evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
2968         route_place(wd->obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
2969      }
2970    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
2971                            "elm,state,busy,stop", "elm");
2972    evas_object_smart_callback_call(wd->obj, SIG_ROUTE_LOADED, NULL);
2973    return EINA_TRUE;
2974 }
2975
2976 static Eina_Bool
2977 _name_complete_cb(void *data, int ev_type __UNUSED__, void *event)
2978 {
2979    Ecore_Con_Event_Url_Complete *ev = event;
2980    Elm_Map_Name *n = (Elm_Map_Name*)data;
2981    Widget_Data *wd = n->wd;
2982
2983    if ((!n) || (!ev)) return EINA_TRUE;
2984    Elm_Map_Name *nn = ecore_con_url_data_get(n->con_url);
2985    ecore_con_url_data_set(n->con_url, NULL);
2986    if (n!=nn) return EINA_TRUE;
2987
2988    if (n->ud.fd) fclose(n->ud.fd);
2989    _parse_name(n);
2990
2991    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
2992                            "elm,state,busy,stop", "elm");
2993    evas_object_smart_callback_call(wd->obj, SIG_NAME_LOADED, NULL);
2994    return EINA_TRUE;
2995 }
2996
2997 static Elm_Map_Name *
2998 _utils_convert_name(const Evas_Object *obj, int method, char *address, double lon, double lat)
2999 {
3000    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3001    Widget_Data *wd = elm_widget_data_get(obj);
3002    Map_Sources_Tab *s = NULL, *ss;
3003    Eina_List *l;
3004    char buf[PATH_MAX];
3005    char *source;
3006    int fd;
3007
3008    if (!wd) return NULL;
3009    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
3010      {
3011         if (!strcmp(ss->name, wd->source_name))
3012           {
3013              s = ss;
3014              break;
3015           }
3016      }
3017    if (!s) return NULL;
3018
3019    Elm_Map_Name *name = ELM_NEW(Elm_Map_Name);
3020    if (!name) return NULL;
3021
3022    snprintf(buf, sizeof(buf), DEST_NAME_XML_FILE);
3023    fd = mkstemp(buf);
3024    if (fd < 0)
3025      {
3026         free(name);
3027         return NULL;
3028      }
3029
3030    name->con_url = ecore_con_url_new(NULL);
3031    name->ud.fname = strdup(buf);
3032    INF("xml file : %s", name->ud.fname);
3033
3034    name->ud.fd = fdopen(fd, "w+");
3035    if ((!name->con_url) || (!name->ud.fd))
3036      {
3037         ecore_con_url_free(name->con_url);
3038         free(name);
3039         return NULL;
3040      }
3041
3042    name->wd = wd;
3043    name->handler = ecore_event_handler_add (ECORE_CON_EVENT_URL_COMPLETE, _name_complete_cb, name);
3044    name->method = method;
3045    if (method == ELM_MAP_NAME_METHOD_SEARCH) name->address = strdup(address);
3046    else if (method == ELM_MAP_NAME_METHOD_REVERSE) name->address = NULL;
3047    name->lon = lon;
3048    name->lat = lat;
3049
3050    source = s->name_url_cb(wd->obj, method, address, lon, lat);
3051    INF("name url = %s", source);
3052
3053    wd->names = eina_list_append(wd->names, name);
3054    ecore_con_url_url_set(name->con_url, source);
3055    ecore_con_url_fd_set(name->con_url, fileno(name->ud.fd));
3056    ecore_con_url_data_set(name->con_url, name);
3057
3058    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
3059                            "elm,state,busy,start", "elm");
3060    evas_object_smart_callback_call(wd->obj, SIG_NAME_LOAD, NULL);
3061    ecore_con_url_get(name->con_url);
3062    if (source) free(source);
3063
3064    return name;
3065
3066 }
3067
3068 static int idnum = 1;
3069
3070 /**
3071  * Add a new Map object
3072  *
3073  * @param parent The parent object
3074  * @return The new object or NULL if it cannot be created
3075  *
3076  * @ingroup Map
3077  */
3078 EAPI Evas_Object *
3079 elm_map_add(Evas_Object *parent)
3080 {
3081    Evas *e;
3082    Widget_Data *wd;
3083    Evas_Coord minw, minh;
3084    Evas_Object *obj;
3085    static Evas_Smart *smart = NULL;
3086    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
3087
3088    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3089
3090    ELM_SET_WIDTYPE(widtype, "map");
3091    elm_widget_type_set(obj, "map");
3092    elm_widget_sub_object_add(parent, obj);
3093    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
3094    elm_widget_data_set(obj, wd);
3095    elm_widget_del_hook_set(obj, _del_hook);
3096    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
3097    elm_widget_theme_hook_set(obj, _theme_hook);
3098    elm_widget_can_focus_set(obj, EINA_TRUE);
3099    elm_widget_event_hook_set(obj, _event_hook);
3100
3101    wd->scr = elm_smart_scroller_add(e);
3102    elm_smart_scroller_widget_set(wd->scr, obj);
3103    elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", "default");
3104    evas_object_smart_callback_add(wd->scr, "scroll", _scr, obj);
3105    evas_object_smart_callback_add(wd->scr, "drag", _scr, obj);
3106    elm_widget_resize_object_set(obj, wd->scr);
3107    elm_smart_scroller_wheel_disabled_set(wd->scr, EINA_TRUE);
3108
3109    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
3110    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
3111    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
3112    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
3113    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
3114
3115    elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
3116    source_init(obj);
3117
3118    wd->obj = obj;
3119    wd->map = evas_map_new(4);
3120    if (!wd->map) return NULL;
3121
3122    wd->markers_max_num = 30;
3123    wd->source_name = eina_stringshare_add("Mapnik");
3124    wd->pinch.level = 1.0;
3125
3126    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
3127    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
3128    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
3129    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
3130
3131    if (!smart)
3132      {
3133         static Evas_Smart_Class sc;
3134
3135         evas_object_smart_clipped_smart_set(&_pan_sc);
3136         sc = _pan_sc;
3137         sc.name = "elm_map_pan";
3138         sc.version = EVAS_SMART_CLASS_VERSION;
3139         sc.add = _pan_add;
3140         sc.del = _pan_del;
3141         sc.resize = _pan_resize;
3142         sc.move = _pan_move;
3143         sc.calculate = _pan_calculate;
3144         smart = evas_smart_class_new(&sc);
3145      }
3146    if (smart)
3147      {
3148         wd->pan_smart = evas_object_smart_add(e, smart);
3149         wd->pan = evas_object_smart_data_get(wd->pan_smart);
3150         wd->pan->wd = wd;
3151      }
3152
3153    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
3154                                      _pan_set, _pan_get, _pan_max_get,
3155                                      _pan_min_get, _pan_child_size_get);
3156
3157    wd->rect = evas_object_rectangle_add(e);
3158    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_RESIZE,
3159                                   _rect_resize_cb, obj);
3160    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_DOWN,
3161                                   _mouse_down, obj);
3162    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_MOVE,
3163                                   _mouse_move, obj);
3164    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_UP,
3165                                   _mouse_up, obj);
3166    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_DOWN,
3167                                   _mouse_multi_down, obj);
3168    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_MOVE,
3169                                   _mouse_multi_move, obj);
3170    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MULTI_UP,
3171                                   _mouse_multi_up, obj);
3172    evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL,
3173                                   _mouse_wheel_cb, obj);
3174
3175    evas_object_smart_member_add(wd->rect, wd->pan_smart);
3176    elm_widget_sub_object_add(obj, wd->rect);
3177    evas_object_show(wd->rect);
3178    evas_object_color_set(wd->rect, 0, 0, 0, 0);
3179
3180    wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
3181    wd->id = ((int)getpid() << 16) | idnum;
3182    idnum++;
3183
3184    wd->tsize = 256;
3185
3186    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
3187                              &minw, &minh);
3188    evas_object_size_hint_min_set(obj, minw, minh);
3189
3190    wd->sep_maps_markers = evas_object_rectangle_add(evas_object_evas_get(obj));
3191    evas_object_smart_member_add(wd->sep_maps_markers, wd->pan_smart);
3192
3193    // TODO: convert Elementary to subclassing of Evas_Smart_Class
3194    // TODO: and save some bytes, making descriptions per-class and not instance!
3195    evas_object_smart_callbacks_descriptions_set(obj, _signals);
3196
3197    if (!ecore_file_download_protocol_available("http://"))
3198      {
3199         ERR("Ecore must be built with curl support for the map widget!");
3200      }
3201
3202    elm_map_zoom_set(obj, 0);
3203    _sizing_eval(obj);
3204
3205    return obj;
3206 }
3207
3208 /**
3209  * Set the zoom level of the map
3210  *
3211  * This sets the zoom level. 0 is the world map and 18 is the maximum zoom.
3212  *
3213  * @param obj The map object
3214  * @param zoom The zoom level to set
3215  *
3216  * @ingroup Map
3217  */
3218 EAPI void
3219 elm_map_zoom_set(Evas_Object *obj, int zoom)
3220 {
3221    ELM_CHECK_WIDTYPE(obj, widtype);
3222    Widget_Data *wd = elm_widget_data_get(obj);
3223    Map_Sources_Tab *s = NULL, *ss;
3224    Eina_List *l, *lr;
3225    Grid *g, *g_zoom = NULL;
3226    Evas_Coord rx, ry, rw, rh;
3227    Evas_Object *p;
3228    Elm_Map_Route *r;
3229    int z = 0, zoom_changed = 0, started = 0;
3230
3231    if ((!wd) || (wd->zoom_animator)) return;
3232    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
3233      {
3234         if (!strcmp(ss->name, wd->source_name))
3235           {
3236              s = ss;
3237              break;
3238           }
3239      }
3240    if (!s) return;
3241
3242    if (zoom < 0 ) zoom = 0;
3243    if (zoom > s->zoom_max) zoom = s->zoom_max;
3244    if (zoom < s->zoom_min) zoom = s->zoom_min;
3245
3246    if ((wd->zoom - zoom) > 0) wd->zoom_method = ZOOM_METHOD_OUT;
3247    else if ((wd->zoom - zoom) < 0) wd->zoom_method = ZOOM_METHOD_IN;
3248    else wd->zoom_method = ZOOM_METHOD_NONE;
3249    if (wd->zoom != zoom ) zoom_changed = 1;
3250    wd->zoom = zoom;
3251    wd->size.ow = wd->size.w;
3252    wd->size.oh = wd->size.h;
3253    elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
3254    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
3255
3256    EINA_LIST_FOREACH(wd->route, lr, r)
3257      {
3258         if (r)
3259           {
3260              EINA_LIST_FOREACH(r->path, l, p)
3261                {
3262                   evas_object_polygon_points_clear(p);
3263                }
3264           }
3265      }
3266
3267    if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
3268      {
3269         int p2w, p2h;
3270         int cumulw, cumulh;
3271
3272         cumulw = wd->tsize;
3273         p2w = 0;
3274         while (cumulw <= rw)
3275           {
3276              p2w++;
3277              cumulw *= 2;
3278           }
3279         p2w--;
3280
3281         cumulh = wd->tsize;
3282         p2h = 0;
3283         while (cumulh <= rh)
3284           {
3285              p2h++;
3286              cumulh *= 2;
3287           }
3288         p2h--;
3289
3290         if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FIT)
3291           {
3292              if (p2w < p2h) z = p2w;
3293              else z = p2h;
3294           }
3295         else if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FILL)
3296           {
3297              if (p2w > p2h) z = p2w;
3298              else z = p2h;
3299           }
3300         wd->zoom = z;
3301      }
3302    wd->size.nw = pow(2.0, wd->zoom) * wd->tsize;
3303    wd->size.nh = pow(2.0, wd->zoom) * wd->tsize;
3304
3305    g = grid_create(obj);
3306    if (g)
3307      {
3308         if (eina_list_count(wd->grids) > 1)
3309           {
3310              g_zoom = eina_list_last(wd->grids)->data;
3311              wd->grids = eina_list_remove(wd->grids, g_zoom);
3312              grid_clear(obj, g_zoom);
3313              free(g_zoom);
3314           }
3315         wd->grids = eina_list_prepend(wd->grids, g);
3316      }
3317    else
3318      {
3319         EINA_LIST_FREE(wd->grids, g)
3320           {
3321              grid_clear(obj, g);
3322              free(g);
3323           }
3324      }
3325
3326    wd->t = 1.0;
3327    if ((wd->size.w > 0) && (wd->size.h > 0))
3328      {
3329         wd->size.spos.x = (double)(rx + (rw / 2)) / (double)wd->size.ow;
3330         wd->size.spos.y = (double)(ry + (rh / 2)) / (double)wd->size.oh;
3331      }
3332    else
3333      {
3334         wd->size.spos.x = 0.5;
3335         wd->size.spos.y = 0.5;
3336      }
3337
3338    if (rw > wd->size.ow) wd->size.spos.x = 0.5;
3339    if (rh > wd->size.oh) wd->size.spos.y = 0.5;
3340    if (wd->size.spos.x > 1.0) wd->size.spos.x = 1.0;
3341    if (wd->size.spos.y > 1.0) wd->size.spos.y = 1.0;
3342
3343    if (wd->paused)
3344      {
3345         zoom_do(obj);
3346         if (wd->calc_job) ecore_job_del(wd->calc_job);
3347         wd->calc_job = ecore_job_add(_calc_job, wd);
3348      }
3349    else
3350      {
3351         if (!wd->zoom_animator)
3352           {
3353              wd->zoom_animator = ecore_animator_add(_zoom_anim, obj);
3354              wd->nosmooth++;
3355              if (wd->nosmooth == 1) _smooth_update(obj);
3356              started = 1;
3357           }
3358      }
3359
3360    if (!wd->paused)
3361      {
3362         if (started) evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL);
3363         if (!wd->zoom_animator) evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
3364      }
3365
3366    if (zoom_changed) evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL);
3367 }
3368
3369 /**
3370  * Get the zoom level of the map
3371  *
3372  * This returns the current zoom level of the map object. Note that if
3373  * you set the fill mode to other than ELM_MAP_ZOOM_MODE_MANUAL
3374  * (which is the default), the zoom level may be changed at any time by the
3375  * map object itself to account for map size and map viewpoer size
3376  *
3377  * @param obj The map object
3378  * @return The current zoom level
3379  *
3380  * @ingroup Map
3381  */
3382 EAPI int
3383 elm_map_zoom_get(const Evas_Object *obj)
3384 {
3385    ELM_CHECK_WIDTYPE(obj, widtype) 0;
3386    Widget_Data *wd = elm_widget_data_get(obj);
3387
3388    if (!wd) return 0;
3389    return wd->zoom;
3390 }
3391
3392 /**
3393  * Set the zoom mode
3394  *
3395  * This sets the zoom mode to manual or one of several automatic levels.
3396  * Manual (ELM_MAP_ZOOM_MODE_MANUAL) means that zoom is set manually by
3397  * elm_map_zoom_set() and will stay at that level until changed by code
3398  * or until zoom mode is changed. This is the default mode.
3399  * The Automatic modes will allow the map object to automatically
3400  * adjust zoom mode based on properties. ELM_MAP_ZOOM_MODE_AUTO_FIT will
3401  * adjust zoom so the map fits inside the scroll frame with no pixels
3402  * outside this area. ELM_MAP_ZOOM_MODE_AUTO_FILL will be similar but
3403  * 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.
3404  *
3405  * @param obj The map object
3406  * @param mode The desired mode
3407  *
3408  * @ingroup Map
3409  */
3410 EAPI void
3411 elm_map_zoom_mode_set(Evas_Object *obj, Elm_Map_Zoom_Mode mode)
3412 {
3413    ELM_CHECK_WIDTYPE(obj, widtype);
3414    Widget_Data *wd = elm_widget_data_get(obj);
3415
3416    if (!wd) return;
3417    if (wd->mode == mode) return;
3418    wd->mode = mode;
3419
3420    if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
3421      {
3422         int tz = wd->zoom;
3423         wd->zoom = 0;
3424         elm_map_zoom_set(wd->obj, tz);
3425      }
3426 }
3427
3428 /**
3429  * Get the zoom mode
3430  *
3431  * This gets the current zoom mode of the map object
3432  *
3433  * @param obj The map object
3434  * @return The current zoom mode
3435  *
3436  * @ingroup Map
3437  */
3438 EAPI Elm_Map_Zoom_Mode
3439 elm_map_zoom_mode_get(const Evas_Object *obj)
3440 {
3441    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_ZOOM_MODE_MANUAL;
3442    Widget_Data *wd = elm_widget_data_get(obj);
3443
3444    if (!wd) return ELM_MAP_ZOOM_MODE_MANUAL;
3445    return wd->mode;
3446 }
3447
3448 /**
3449  * Centers the map at @p lon @p lat using an animation to scroll.
3450  *
3451  * @param obj The map object
3452  * @param lon Longitude to center at
3453  * @param lon Latitude to center at
3454  *
3455  * @ingroup Map
3456  */
3457 EAPI void
3458 elm_map_geo_region_bring_in(Evas_Object *obj, double lon, double lat)
3459 {
3460    ELM_CHECK_WIDTYPE(obj, widtype);
3461    Widget_Data *wd = elm_widget_data_get(obj);
3462    int rx, ry, rw, rh;
3463
3464    if (!wd) return;
3465    elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
3466    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
3467
3468    rx = rx - rw / 2;
3469    ry = ry - rh / 2;
3470
3471    if (wd->zoom_animator)
3472      {
3473         wd->nosmooth--;
3474         if (!wd->nosmooth) _smooth_update(obj);
3475         ecore_animator_del(wd->zoom_animator);
3476         wd->zoom_animator = NULL;
3477         zoom_do(obj);
3478         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
3479      }
3480    elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh);
3481
3482    wd->center_on.enabled = EINA_TRUE;
3483    wd->center_on.lon = lon;
3484    wd->center_on.lat = lat;
3485 }
3486
3487 /**
3488  * Move the map to the current coordinates.
3489  *
3490  * This move the map to the current coordinates. The map will be centered on these coordinates.
3491  *
3492  * @param obj The map object
3493  * @param lat The latitude.
3494  * @param lon The longitude.
3495  *
3496  * @ingroup Map
3497  */
3498 EAPI void
3499 elm_map_geo_region_show(Evas_Object *obj, double lon, double lat)
3500 {
3501    ELM_CHECK_WIDTYPE(obj, widtype);
3502    Widget_Data *wd = elm_widget_data_get(obj);
3503    int rx, ry, rw, rh;
3504
3505    if (!wd) return;
3506    elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
3507    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
3508
3509    rx = rx - rw / 2;
3510    ry = ry - rh / 2;
3511
3512    if (wd->zoom_animator)
3513      {
3514         wd->nosmooth--;
3515         ecore_animator_del(wd->zoom_animator);
3516         wd->zoom_animator = NULL;
3517         zoom_do(obj);
3518         evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
3519      }
3520    elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh);
3521
3522    wd->center_on.enabled = EINA_TRUE;
3523    wd->center_on.lon = lon;
3524    wd->center_on.lat = lat;
3525 }
3526
3527 /**
3528  * Get the current coordinates of the map.
3529  *
3530  * This gets the current coordinates of the map object.
3531  *
3532  * @param obj The map object
3533  * @param lat The latitude.
3534  * @param lon The longitude.
3535  *
3536  * @ingroup Map
3537  */
3538 EAPI void
3539 elm_map_geo_region_get(const Evas_Object *obj, double *lon, double *lat)
3540 {
3541    ELM_CHECK_WIDTYPE(obj, widtype);
3542    Widget_Data *wd = elm_widget_data_get(obj);
3543    Evas_Coord sx, sy, sw, sh;
3544
3545    if (!wd) return;
3546    elm_smart_scroller_child_pos_get(wd->scr, &sx, &sy);
3547    elm_smart_scroller_child_viewport_size_get(wd->scr, &sw, &sh);
3548    sx += sw / 2;
3549    sy += sh / 2;
3550
3551    elm_map_utils_convert_coord_into_geo(obj, sx, sy, wd->size.w, lon, lat);
3552 }
3553
3554 /**
3555  * Set the paused state for map
3556  *
3557  * This sets the paused state to on (1) or off (0) for map. The default
3558  * is off. This will stop zooming using animation change zoom levels and
3559  * change instantly. This will stop any existing animations that are running.
3560  *
3561  * @param obj The map object
3562  * @param paused The pause state to set
3563  *
3564  * @ingroup Map
3565  */
3566 EAPI void
3567 elm_map_paused_set(Evas_Object *obj, Eina_Bool paused)
3568 {
3569    ELM_CHECK_WIDTYPE(obj, widtype);
3570    Widget_Data *wd = elm_widget_data_get(obj);
3571
3572    if (!wd) return;
3573    if (wd->paused == !!paused) return;
3574    wd->paused = paused;
3575    if (wd->paused)
3576      {
3577         if (wd->zoom_animator)
3578           {
3579              if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
3580              wd->zoom_animator = NULL;
3581              zoom_do(obj);
3582              evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
3583           }
3584      }
3585 }
3586
3587 /**
3588  * Set the paused state for the markers
3589  *
3590  * This sets the paused state to on (1) or off (0) for the markers. The default
3591  * is off. This will stop displaying the markers during change zoom levels. Set
3592  * to on if you have a large number of markers.
3593  *
3594  * @param obj The map object
3595  * @param paused The pause state to set
3596  *
3597  * @ingroup Map
3598  */
3599 EAPI void
3600 elm_map_paused_markers_set(Evas_Object *obj, Eina_Bool paused)
3601 {
3602    ELM_CHECK_WIDTYPE(obj, widtype);
3603    Widget_Data *wd = elm_widget_data_get(obj);
3604
3605    if (!wd) return;
3606    if (wd->paused_markers == !!paused) return;
3607    wd->paused_markers = paused;
3608 }
3609
3610 /**
3611  * Get the paused state for map
3612  *
3613  * This gets the current paused state for the map object.
3614  *
3615  * @param obj The map object
3616  * @return The current paused state
3617  *
3618  * @ingroup Map
3619  */
3620 EAPI Eina_Bool
3621 elm_map_paused_get(const Evas_Object *obj)
3622 {
3623    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3624    Widget_Data *wd = elm_widget_data_get(obj);
3625
3626    if (!wd) return EINA_FALSE;
3627    return wd->paused;
3628 }
3629
3630 /**
3631  * Get the paused state for the markers
3632  *
3633  * This gets the current paused state for the markers object.
3634  *
3635  * @param obj The map object
3636  * @return The current paused state
3637  *
3638  * @ingroup Map
3639  */
3640 EAPI Eina_Bool
3641 elm_map_paused_markers_get(const Evas_Object *obj)
3642 {
3643    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3644    Widget_Data *wd = elm_widget_data_get(obj);
3645
3646    if (!wd) return EINA_FALSE;
3647    return wd->paused_markers;
3648 }
3649
3650 /**
3651  * Get the information of downloading status
3652  *
3653  * This gets the current downloading status for the map object.
3654  *
3655  * @param obj The map object
3656  * @param try_num the number of download trying map
3657  * @param finish_num the number of downloaded map
3658  *
3659  * @ingroup Map
3660  */
3661
3662 EAPI void
3663 elm_map_utils_downloading_status_get(const Evas_Object *obj, int *try_num, int *finish_num)
3664 {
3665    ELM_CHECK_WIDTYPE(obj, widtype);
3666    Widget_Data *wd = elm_widget_data_get(obj);
3667
3668    if (!wd) return;
3669    if (try_num)
3670      {
3671         *try_num = wd->try_num;
3672      }
3673
3674    if (finish_num)
3675      {
3676         *finish_num = wd->finish_num;
3677      }
3678 }
3679 /**
3680  * Convert a pixel coordinate (x,y) into a geographic coordinate (longitude, latitude).
3681  *
3682  * @param obj The map object
3683  * @param x the coordinate
3684  * @param y the coordinate
3685  * @param size the size in pixels of the map. The map is a square and generally his size is : pow(2.0, zoom)*256.
3686  * @param lon the longitude correspond to x
3687  * @param lat the latitude correspond to y
3688  *
3689  * @ingroup Map
3690  */
3691 EAPI void
3692 elm_map_utils_convert_coord_into_geo(const Evas_Object *obj, int x, int y, int size, double *lon, double *lat)
3693 {
3694    ELM_CHECK_WIDTYPE(obj, widtype);
3695    Widget_Data *wd = elm_widget_data_get(obj);
3696    Map_Sources_Tab *s = NULL, *ss;
3697    Eina_List *l;
3698
3699    if (!wd) return;
3700    int zoom = floor(log(size/256) / log(2));
3701    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
3702      {
3703         if (!strcmp(ss->name, wd->source_name))
3704           {
3705              s = ss;
3706              break;
3707           }
3708      }
3709    if ((s) && (s->coord_into_geo))
3710      {
3711         if (s->coord_into_geo(obj, zoom, x, y, size, lon, lat)) return;
3712      }
3713
3714    if (lon)
3715      {
3716         *lon = x / (double)size * 360.0 - 180;
3717      }
3718    if (lat)
3719      {
3720         double n = ELM_PI - 2.0 * ELM_PI * y / size;
3721         *lat = 180.0 / ELM_PI * atan(0.5 * (exp(n) - exp(-n)));
3722      }
3723 }
3724
3725 /**
3726  * Convert a geographic coordinate (longitude, latitude) into a pixel coordinate (x, y).
3727  *
3728  * @param obj The map object
3729  * @param lon the longitude
3730  * @param lat the latitude
3731  * @param size the size in pixels of the map. The map is a square and generally his size is : pow(2.0, zoom)*256.
3732  * @param x the coordinate correspond to the longitude
3733  * @param y the coordinate correspond to the latitude
3734  *
3735  * @ingroup Map
3736  */
3737 EAPI void
3738 elm_map_utils_convert_geo_into_coord(const Evas_Object *obj, double lon, double lat, int size, int *x, int *y)
3739 {
3740    ELM_CHECK_WIDTYPE(obj, widtype);
3741    Widget_Data *wd = elm_widget_data_get(obj);
3742    Map_Sources_Tab *s = NULL, *ss;
3743    Eina_List *l;
3744
3745    if (!wd) return;
3746    int zoom = floor(log(size/256) / log(2));
3747    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
3748      {
3749         if (!strcmp(ss->name, wd->source_name))
3750           {
3751              s = ss;
3752              break;
3753           }
3754      }
3755    if ((s) && (s->geo_into_coord))
3756      {
3757         if (s->geo_into_coord(obj, zoom, lon, lat, size, x, y)) return;
3758      }
3759
3760    if (x)
3761      *x = floor((lon + 180.0) / 360.0 * size);
3762    if (y)
3763      *y = floor((1.0 - log( tan(lat * ELM_PI/180.0) + 1.0 / cos(lat * ELM_PI/180.0)) / ELM_PI) / 2.0 * size);
3764 }
3765
3766 /**
3767  * Convert a geographic coordinate (longitude, latitude) into a name (address).
3768  *
3769  * @param obj The map object
3770  * @param lon the longitude
3771  * @param lat the latitude
3772  *
3773  * @return name the address
3774  *
3775  * @ingroup Map
3776  */
3777 EAPI Elm_Map_Name *
3778 elm_map_utils_convert_coord_into_name(const Evas_Object *obj, double lon, double lat)
3779 {
3780    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3781    return _utils_convert_name(obj, ELM_MAP_NAME_METHOD_REVERSE, NULL, lon, lat);
3782 }
3783
3784 /**
3785  * Convert a name (address) into a geographic coordinate (longitude, latitude).
3786  *
3787  * @param obj The map object
3788  * @param name the address
3789  * @param lat the latitude correspond to y
3790  *
3791  * @return name the address
3792  *
3793  * @ingroup Map
3794  */
3795 EAPI Elm_Map_Name *
3796 elm_map_utils_convert_name_into_coord(const Evas_Object *obj, char *address)
3797 {
3798    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3799    if (!address) return NULL;
3800    return _utils_convert_name(obj, ELM_MAP_NAME_METHOD_SEARCH, address, 0.0, 0.0);
3801 }
3802
3803 /**
3804  * Convert a pixel coordinate into a roated pixcel coordinate.
3805  *
3806  * @param obj The map object
3807  * @param x x to rotate.
3808  * @param y y to rotate.
3809  * @param cx rotation's center horizontal position.
3810  * @param cy rotation's center vertical position.
3811  * @param degree amount of degrees from 0.0 to 360.0 to rotate arount Z axis.
3812  * @param xx rotated x.
3813  * @param yy rotated y.
3814  *
3815  * @ingroup Map
3816  */
3817 EAPI void
3818 elm_map_utils_rotate_coord(const Evas_Object *obj __UNUSED__, const Evas_Coord x, const Evas_Coord y, const Evas_Coord cx, const Evas_Coord cy, const double degree, Evas_Coord *xx, Evas_Coord *yy)
3819 {
3820    if ((!xx) || (!yy)) return;
3821
3822    double r = (degree * M_PI) / 180.0;
3823    double tx, ty, ttx, tty;
3824
3825    tx = x - cx;
3826    ty = y - cy;
3827
3828    ttx = tx * cos(r);
3829    tty = tx * sin(r);
3830    tx = ttx + (ty * cos(r + M_PI_2));
3831    ty = tty + (ty * sin(r + M_PI_2));
3832
3833    *xx = tx + cx;
3834    *yy = ty + cy;
3835 }
3836
3837 /**
3838  * Add a marker on the map
3839  *
3840  * @param obj The map object
3841  * @param lon the longitude
3842  * @param lat the latitude
3843  * @param clas the class to use
3844  * @param clas_group the class group
3845  * @param data the data passed to the callbacks
3846  *
3847  * @return The marker object
3848  *
3849  * @ingroup Map
3850  */
3851 EAPI Elm_Map_Marker *
3852 elm_map_marker_add(Evas_Object *obj, double lon, double lat, Elm_Map_Marker_Class *clas, Elm_Map_Group_Class *clas_group, void *data)
3853 {
3854    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3855    Widget_Data *wd = elm_widget_data_get(obj);
3856    int i, j;
3857    Eina_List *l;
3858    Marker_Group *group;
3859    int mpi, mpj;
3860    int tabi[9];
3861    int tabj[9];
3862    const char *s;
3863    const char *style;
3864    Evas_Object *o;
3865
3866    if (!wd) return NULL;
3867    EINA_SAFETY_ON_NULL_RETURN_VAL(clas_group, NULL);
3868    EINA_SAFETY_ON_NULL_RETURN_VAL(clas, NULL);
3869
3870    Elm_Map_Marker *marker = ELM_NEW(Elm_Map_Marker);
3871
3872    marker->wd = wd;
3873    marker->clas = clas;
3874    marker->clas_group = clas_group;
3875    marker->longitude = lon;
3876    marker->latitude = lat;
3877    marker->data = data;
3878
3879    tabi[1] = tabi[4] = tabi[6] = -1;
3880    tabi[2] = tabi[0] = tabi[7] = 0;
3881    tabi[3] = tabi[5] = tabi[8] = 1;
3882
3883    tabj[1] = tabj[2] = tabj[3] = -1;
3884    tabj[4] = tabj[0] = tabj[5] = 0;
3885    tabj[6] = tabj[7] = tabj[8] = 1;
3886
3887    if (!clas_group->priv.set)
3888      {
3889         style = "radio";
3890         if (marker->clas_group && marker->clas_group->style)
3891           style = marker->clas_group->style;
3892
3893         o = edje_object_add(evas_object_evas_get(obj));
3894         _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
3895         s = edje_object_data_get(o, "size_w");
3896         if (s) clas_group->priv.edje_w = atoi(s);
3897         else clas_group->priv.edje_w = 0;
3898         s = edje_object_data_get(o, "size_h");
3899         if (s) clas_group->priv.edje_h = atoi(s);
3900         else clas_group->priv.edje_h = 0;
3901         s = edje_object_data_get(o, "size_max_w");
3902         if (s) clas_group->priv.edje_max_w = atoi(s);
3903         else clas_group->priv.edje_max_w = 0;
3904         s = edje_object_data_get(o, "size_max_h");
3905         if (s) clas_group->priv.edje_max_h = atoi(s);
3906         else clas_group->priv.edje_max_h = 0;
3907         evas_object_del(o);
3908
3909         clas_group->priv.set = EINA_TRUE;
3910      }
3911
3912    if (!clas->priv.set)
3913      {
3914         style = "radio";
3915         if (marker->clas && marker->clas->style)
3916           style = marker->clas->style;
3917
3918         o = edje_object_add(evas_object_evas_get(obj));
3919         _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
3920         s = edje_object_data_get(o, "size_w");
3921         if (s) clas->priv.edje_w = atoi(s);
3922         else clas->priv.edje_w = 0;
3923         s = edje_object_data_get(o, "size_h");
3924         if (s) clas->priv.edje_h = atoi(s);
3925         else clas->priv.edje_h = 0;
3926         evas_object_del(o);
3927
3928         clas->priv.set = EINA_TRUE;
3929      }
3930
3931    for (i = clas_group->zoom_displayed; i <= ZOOM_MAX; i++)
3932      {
3933         elm_map_utils_convert_geo_into_coord(obj, lon, lat, pow(2.0, i)*wd->tsize,
3934                                              &(marker->x[i]), &(marker->y[i]));
3935
3936         //search in the matrixsparse the region where the marker will be
3937         mpi = marker->x[i] / wd->tsize;
3938         mpj = marker->y[i] / wd->tsize;
3939
3940         if (!wd->markers[i])
3941           {
3942              int size =  pow(2.0, i);
3943              wd->markers[i] = eina_matrixsparse_new(size, size, NULL, NULL);
3944           }
3945
3946         group = NULL;
3947         if (i <= clas_group->zoom_grouped)
3948           {
3949              for (j = 0, group = NULL; j < 9 && !group; j++)
3950                {
3951                   EINA_LIST_FOREACH(eina_matrixsparse_data_idx_get(wd->markers[i], mpj + tabj[j], mpi + tabi[j]),
3952                                     l, group)
3953                     {
3954                        if (group->clas == marker->clas_group
3955                            && ELM_RECTS_INTERSECT(marker->x[i]-clas->priv.edje_w/4,
3956                                                   marker->y[i]-clas->priv.edje_h/4, clas->priv.edje_w, clas->priv.edje_h,
3957                                                   group->x-group->w/4, group->y-group->h/4, group->w, group->h))
3958                          {
3959                             group->markers = eina_list_append(group->markers, marker);
3960                             group->update_nbelems = EINA_TRUE;
3961                             group->update_resize = EINA_TRUE;
3962
3963                             group->sum_x += marker->x[i];
3964                             group->sum_y += marker->y[i];
3965                             group->x = group->sum_x / eina_list_count(group->markers);
3966                             group->y = group->sum_y / eina_list_count(group->markers);
3967
3968                             group->w = group->clas->priv.edje_w + group->clas->priv.edje_w/8.
3969                                * eina_list_count(group->markers);
3970                             group->h = group->clas->priv.edje_h + group->clas->priv.edje_h/8.
3971                                * eina_list_count(group->markers);
3972                             if (group->w > group->clas->priv.edje_max_w) group->w = group->clas->priv.edje_max_w;
3973                             if (group->h > group->clas->priv.edje_max_h) group->h = group->clas->priv.edje_max_h;
3974
3975                             if (group->obj && eina_list_count(group->markers) == 2)
3976                               {
3977                                  _group_object_free(group);
3978                                  _group_object_create(group);
3979                               }
3980                             if (group->bubble)
3981                               _group_bubble_content_update(group);
3982
3983                             break;
3984                          }
3985                     }
3986                }
3987           }
3988         if (!group)
3989           {
3990              group = calloc(1, sizeof(Marker_Group));
3991              group->wd = wd;
3992              group->sum_x = marker->x[i];
3993              group->sum_y = marker->y[i];
3994              group->x = marker->x[i];
3995              group->y = marker->y[i];
3996              group->w = clas_group->priv.edje_w;
3997              group->h = clas_group->priv.edje_h;
3998              group->clas = clas_group;
3999
4000              group->markers = eina_list_append(group->markers, marker);
4001              group->update_nbelems = EINA_TRUE;
4002              group->update_resize = EINA_TRUE;
4003
4004              eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
4005
4006              if (!group->cell)
4007                {
4008                   l = eina_list_append(NULL, group);
4009                   eina_matrixsparse_data_idx_set(wd->markers[i], mpj, mpi, l);
4010                   eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
4011                }
4012              else
4013                {
4014                   l = eina_matrixsparse_cell_data_get(group->cell);
4015                   l = eina_list_append(l, group);
4016                   eina_matrixsparse_cell_data_set(group->cell, l);
4017                }
4018           }
4019         marker->groups[i] = group;
4020      }
4021
4022    if (wd->grids)
4023      {
4024         Evas_Coord ox, oy, ow, oh;
4025         evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
4026         marker_place(obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
4027      }
4028
4029    return marker;
4030 }
4031
4032 /**
4033  * Remove a marker from the map
4034  *
4035  * @param marker The marker to remove
4036  *
4037  * @ingroup Map
4038  */
4039 EAPI void
4040 elm_map_marker_remove(Elm_Map_Marker *marker)
4041 {
4042    int i;
4043    Eina_List *groups;
4044    Widget_Data *wd;
4045
4046    EINA_SAFETY_ON_NULL_RETURN(marker);
4047    wd = marker->wd;
4048    if (!wd) return;
4049    for (i = marker->clas_group->zoom_displayed; i <= ZOOM_MAX; i++)
4050      {
4051         marker->groups[i]->markers = eina_list_remove(marker->groups[i]->markers, marker);
4052         if (!eina_list_count(marker->groups[i]->markers))
4053           {
4054              groups = eina_matrixsparse_cell_data_get(marker->groups[i]->cell);
4055              groups = eina_list_remove(groups, marker->groups[i]);
4056              eina_matrixsparse_cell_data_set(marker->groups[i]->cell, groups);
4057
4058              _group_object_free(marker->groups[i]);
4059              _group_bubble_free(marker->groups[i]);
4060              free(marker->groups[i]);
4061           }
4062         else
4063           {
4064              marker->groups[i]->sum_x -= marker->x[i];
4065              marker->groups[i]->sum_y -= marker->y[i];
4066
4067              marker->groups[i]->x = marker->groups[i]->sum_x / eina_list_count(marker->groups[i]->markers);
4068              marker->groups[i]->y = marker->groups[i]->sum_y / eina_list_count(marker->groups[i]->markers);
4069
4070              marker->groups[i]->w = marker->groups[i]->clas->priv.edje_w
4071                 + marker->groups[i]->clas->priv.edje_w/8. * eina_list_count(marker->groups[i]->markers);
4072              marker->groups[i]->h = marker->groups[i]->clas->priv.edje_h
4073                 + marker->groups[i]->clas->priv.edje_h/8. * eina_list_count(marker->groups[i]->markers);
4074              if (marker->groups[i]->w > marker->groups[i]->clas->priv.edje_max_w)
4075                marker->groups[i]->w = marker->groups[i]->clas->priv.edje_max_w;
4076              if (marker->groups[i]->h > marker->groups[i]->clas->priv.edje_max_h)
4077                marker->groups[i]->h = marker->groups[i]->clas->priv.edje_max_h;
4078
4079              if ((marker->groups[i]->obj) && (eina_list_count(marker->groups[i]->markers) == 1))
4080                {
4081                   _group_object_free(marker->groups[i]);
4082                   _group_object_create(marker->groups[i]);
4083                }
4084           }
4085      }
4086
4087    if ((marker->content) && (marker->clas->func.del))
4088      marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
4089    else if (marker->content)
4090      evas_object_del(marker->content);
4091
4092    free(marker);
4093
4094    if (wd->grids)
4095      {
4096         Evas_Coord ox, oy, ow, oh;
4097         evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
4098         marker_place(wd->obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
4099      }
4100 }
4101
4102 /**
4103  * Get the current coordinates of the marker.
4104  *
4105  * @param marker marker.
4106  * @param lat The latitude.
4107  * @param lon The longitude.
4108  *
4109  * @ingroup Map
4110  */
4111 EAPI void
4112 elm_map_marker_region_get(const Elm_Map_Marker *marker, double *lon, double *lat)
4113 {
4114    EINA_SAFETY_ON_NULL_RETURN(marker);
4115    if (lon) *lon = marker->longitude;
4116    if (lat) *lat = marker->latitude;
4117 }
4118
4119 /**
4120  * Move the map to the coordinate of the marker.
4121  *
4122  * @param marker The marker where the map will be center.
4123  *
4124  * @ingroup Map
4125  */
4126 EAPI void
4127 elm_map_marker_bring_in(Elm_Map_Marker *marker)
4128 {
4129    EINA_SAFETY_ON_NULL_RETURN(marker);
4130    elm_map_geo_region_bring_in(marker->wd->obj, marker->longitude, marker->latitude);
4131 }
4132
4133 /**
4134  * Move the map to the coordinate of the marker.
4135  *
4136  * @param marker The marker where the map will be center.
4137  *
4138  * @ingroup Map
4139  */
4140 EAPI void
4141 elm_map_marker_show(Elm_Map_Marker *marker)
4142 {
4143    EINA_SAFETY_ON_NULL_RETURN(marker);
4144    elm_map_geo_region_show(marker->wd->obj, marker->longitude, marker->latitude);
4145 }
4146
4147 /**
4148  * Move and zoom the map to display a list of markers.
4149  *
4150  * The map will be centered on the center point of the markers in the list. Then
4151  * the map will be zoomed in order to fit the markers using the maximum zoom which
4152  * allows display of all the markers.
4153  *
4154  * @param markers The list of markers (list of Elm_Map_Marker *)
4155  *
4156  * @ingroup Map
4157  */
4158 EAPI void
4159 elm_map_markers_list_show(Eina_List *markers)
4160 {
4161    int zoom;
4162    double lon, lat;
4163    Eina_List *l;
4164    Elm_Map_Marker *marker, *m_max_lon = NULL, *m_max_lat = NULL, *m_min_lon = NULL, *m_min_lat = NULL;
4165    Evas_Coord rw, rh, xc, yc;
4166    Widget_Data *wd;
4167    Map_Sources_Tab *s = NULL, *ss;
4168
4169    EINA_SAFETY_ON_NULL_RETURN(markers);
4170    EINA_LIST_FOREACH(markers, l, marker)
4171      {
4172         wd = marker->wd;
4173
4174         if ((!m_min_lon) || (marker->longitude < m_min_lon->longitude))
4175           m_min_lon = marker;
4176
4177         if ((!m_max_lon) || (marker->longitude > m_max_lon->longitude))
4178           m_max_lon = marker;
4179
4180         if ((!m_min_lat) || (marker->latitude > m_min_lat->latitude))
4181           m_min_lat = marker;
4182
4183         if ((!m_max_lat) || (marker->latitude < m_max_lat->latitude))
4184           m_max_lat = marker;
4185      }
4186
4187    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4188      {
4189         if (!strcmp(ss->name, wd->source_name))
4190           {
4191              s = ss;
4192              break;
4193           }
4194      }
4195    if (!s) return;
4196
4197    lon = (m_max_lon->longitude - m_min_lon->longitude) / 2. + m_min_lon->longitude;
4198    lat = (m_max_lat->latitude - m_min_lat->latitude) / 2. + m_min_lat->latitude;
4199
4200    elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
4201    for (zoom = s->zoom_max; zoom>s->zoom_min; zoom--)
4202      {
4203         Evas_Coord size = pow(2.0, zoom)*wd->tsize;
4204         elm_map_utils_convert_geo_into_coord(wd->obj, lon, lat, size, &xc, &yc);
4205
4206         if ((m_min_lon->x[zoom] - wd->marker_max_w >= xc-rw/2)
4207             && (m_min_lat->y[zoom] - wd->marker_max_h >= yc-rh/2)
4208             && (m_max_lon->x[zoom] + wd->marker_max_w <= xc+rw/2)
4209             && (m_max_lat->y[zoom] + wd->marker_max_h <= yc+rh/2))
4210           break;
4211      }
4212
4213    elm_map_geo_region_show(wd->obj, lon, lat);
4214    elm_map_zoom_set(wd->obj, zoom);
4215 }
4216
4217 /**
4218  * Set the maximum numbers of markers display in a group.
4219  *
4220  * A group can have a long list of markers, consequently the creation of the content
4221  * of the bubble can be very slow. In order to avoid this, a maximum number of items
4222  * is displayed in a bubble. By default this number is 30.
4223  *
4224  * @param obj The map object.
4225  * @param max The maximum numbers of items displayed in a bubble.
4226  *
4227  * @ingroup Map
4228  */
4229 EAPI void
4230 elm_map_max_marker_per_group_set(Evas_Object *obj, int max)
4231 {
4232    ELM_CHECK_WIDTYPE(obj, widtype);
4233    Widget_Data *wd = elm_widget_data_get(obj);
4234
4235    if (!wd) return;
4236    wd->markers_max_num = max;
4237 }
4238
4239 /**
4240  * Return the evas object getting from the ElmMapMarkerGetFunc callback
4241  *
4242  * @param marker The marker.
4243  * @return Return the evas object if it exists, else NULL.
4244  *
4245  * @ingroup Map
4246  */
4247 EAPI Evas_Object *
4248 elm_map_marker_object_get(const Elm_Map_Marker *marker)
4249 {
4250    EINA_SAFETY_ON_NULL_RETURN_VAL(marker, NULL);
4251    return marker->content;
4252 }
4253
4254 /**
4255  * Update the marker
4256  *
4257  * @param marker The marker.
4258  *
4259  * @ingroup Map
4260  */
4261 EAPI void
4262 elm_map_marker_update(Elm_Map_Marker *marker)
4263 {
4264    EINA_SAFETY_ON_NULL_RETURN(marker);
4265    if (marker->content)
4266      {
4267         if (marker->clas->func.del)
4268           marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
4269         else
4270           evas_object_del(marker->content);
4271         marker->content = NULL;
4272         _group_bubble_content_update(marker->groups[marker->wd->zoom]);
4273      }
4274 }
4275
4276 /**
4277  * Close all opened bubbles
4278  *
4279  * @param obj The map object
4280  *
4281  * @ingroup Map
4282  */
4283 EAPI void
4284 elm_map_bubbles_close(Evas_Object *obj)
4285 {
4286    ELM_CHECK_WIDTYPE(obj, widtype);
4287    Widget_Data *wd = elm_widget_data_get(obj);
4288    Marker_Group *group;
4289    Eina_List *l, *l_next;
4290
4291    if (!wd) return;
4292    EINA_LIST_FOREACH_SAFE(wd->opened_bubbles, l, l_next, group)
4293       _group_bubble_free(group);
4294 }
4295
4296 /**
4297  * Create a group class.
4298  *
4299  * Each marker must be associated to a group class. Marker with the same group are grouped if they are close.
4300  * The group class defines the style of the marker when a marker is grouped to others markers.
4301  *
4302  * @param obj The map object
4303  * @return Returns the new group class
4304  *
4305  * @ingroup Map
4306  */
4307 EAPI Elm_Map_Group_Class *
4308 elm_map_group_class_new(Evas_Object *obj)
4309 {
4310    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4311    Widget_Data *wd = elm_widget_data_get(obj);
4312
4313    if (!wd) return NULL;
4314    Elm_Map_Group_Class *clas = calloc(1, sizeof(Elm_Map_Group_Class));
4315    clas->zoom_grouped = ZOOM_MAX;
4316    wd->groups_clas = eina_list_append(wd->groups_clas, clas);
4317    return clas;
4318 }
4319
4320 /**
4321  * Set the style of a group class (radio, radio2 or empty)
4322  *
4323  * @param clas the group class
4324  * @param style the new style
4325  *
4326  * @ingroup Map
4327  */
4328 EAPI void
4329 elm_map_group_class_style_set(Elm_Map_Group_Class *clas, const char *style)
4330 {
4331    EINA_SAFETY_ON_NULL_RETURN(clas);
4332    eina_stringshare_replace(&clas->style, style);
4333 }
4334
4335 /**
4336  * Set the icon callback of a group class.
4337  *
4338  * A custom icon can be displayed in a marker. The function @ref icon_get must return this icon.
4339  *
4340  * @param clas the group class
4341  * @param icon_get the callback to create the icon
4342  *
4343  * @ingroup Map
4344  */
4345 EAPI void
4346 elm_map_group_class_icon_cb_set(Elm_Map_Group_Class *clas, ElmMapGroupIconGetFunc icon_get)
4347 {
4348    EINA_SAFETY_ON_NULL_RETURN(clas);
4349    clas->func.icon_get = icon_get;
4350 }
4351
4352 /**
4353  * Set the data associated to the group class (radio, radio2 or empty)
4354  *
4355  * @param clas the group class
4356  * @param data the new user data
4357  *
4358  * @ingroup Map
4359  */
4360 EAPI void
4361 elm_map_group_class_data_set(Elm_Map_Group_Class *clas, void *data)
4362 {
4363    EINA_SAFETY_ON_NULL_RETURN(clas);
4364    clas->data = data;
4365 }
4366
4367 /**
4368  * Set the zoom from where the markers are displayed.
4369  *
4370  * Markers will not be displayed for a zoom less than @ref zoom
4371  *
4372  * @param clas the group class
4373  * @param zoom the zoom
4374  *
4375  * @ingroup Map
4376  */
4377 EAPI void
4378 elm_map_group_class_zoom_displayed_set(Elm_Map_Group_Class *clas, int zoom)
4379 {
4380    EINA_SAFETY_ON_NULL_RETURN(clas);
4381    clas->zoom_displayed = zoom;
4382 }
4383
4384 /**
4385  * Set the zoom from where the markers are no more grouped.
4386  *
4387  * @param clas the group class
4388  * @param zoom the zoom
4389  *
4390  * @ingroup Map
4391  */
4392 EAPI void
4393 elm_map_group_class_zoom_grouped_set(Elm_Map_Group_Class *clas, int zoom)
4394 {
4395    EINA_SAFETY_ON_NULL_RETURN(clas);
4396    clas->zoom_grouped = zoom;
4397 }
4398
4399 /**
4400  * Set if the markers associated to the group class @clas are hidden or not.
4401  * If @ref hide is true the markers will be hidden.
4402  *
4403  * @param clas the group class
4404  * @param hide if true the markers will be hidden, else they will be displayed.
4405  *
4406  * @ingroup Map
4407  */
4408 EAPI void
4409 elm_map_group_class_hide_set(Evas_Object *obj, Elm_Map_Group_Class *clas, Eina_Bool hide)
4410 {
4411    ELM_CHECK_WIDTYPE(obj, widtype);
4412    Widget_Data *wd = elm_widget_data_get(obj);
4413
4414    if (!wd) return;
4415    EINA_SAFETY_ON_NULL_RETURN(clas);
4416    if (clas->hide == hide) return;
4417    clas->hide = hide;
4418    if (wd->grids)
4419      {
4420         Evas_Coord ox, oy, ow, oh;
4421         evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
4422         marker_place(obj, eina_list_data_get(wd->grids), wd->pan_x, wd->pan_y, ox, oy, ow, oh);
4423      }
4424 }
4425
4426
4427 /**
4428  * Create a marker class.
4429  *
4430  * Each marker must be associated to a class.
4431  * The class defines the style of the marker when a marker is displayed alone (not grouped).
4432  *
4433  * @param obj The map object
4434  * @return Returns the new class
4435  *
4436  * @ingroup Map
4437  */
4438 EAPI Elm_Map_Marker_Class *
4439 elm_map_marker_class_new(Evas_Object *obj)
4440 {
4441    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4442    Widget_Data *wd = elm_widget_data_get(obj);
4443
4444    if (!wd) return NULL;
4445    Elm_Map_Marker_Class *clas = calloc(1, sizeof(Elm_Map_Marker_Class));
4446    wd->markers_clas = eina_list_append(wd->markers_clas, clas);
4447    return clas;
4448 }
4449
4450 /**
4451  * Set the style of a class (radio, radio2 or empty)
4452  *
4453  * @param clas the group class
4454  * @param style the new style
4455  *
4456  * @ingroup Map
4457  */
4458 EAPI void
4459 elm_map_marker_class_style_set(Elm_Map_Marker_Class *clas, const char *style)
4460 {
4461    EINA_SAFETY_ON_NULL_RETURN(clas);
4462    eina_stringshare_replace(&clas->style, style);
4463 }
4464
4465 /**
4466  * Set the icon callback of a class.
4467  *
4468  * A custom icon can be displayed in a marker. The function @ref icon_get must return this icon.
4469  *
4470  * @param clas the group class
4471  * @param icon_get the callback to create the icon
4472  *
4473  * @ingroup Map
4474  */
4475 EAPI void
4476 elm_map_marker_class_icon_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerIconGetFunc icon_get)
4477 {
4478    EINA_SAFETY_ON_NULL_RETURN(clas);
4479    clas->func.icon_get = icon_get;
4480 }
4481
4482 /**
4483  *
4484  * Set the callback of the content of the bubble.
4485  *
4486  * When the user click on a marker, a bubble is displayed with a content.
4487  * The callback @ref get musst return this content. It can be NULL.
4488  *
4489  * @param clas the group class
4490  * @param get the callback to create the content
4491  *
4492  * @ingroup Map
4493  */
4494 EAPI void
4495 elm_map_marker_class_get_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerGetFunc get)
4496 {
4497    EINA_SAFETY_ON_NULL_RETURN(clas);
4498    clas->func.get = get;
4499 }
4500
4501 /**
4502  * Set the callback of the content of delete the object created by the callback "get".
4503  *
4504  * If this callback is defined the user will have to delete (or not) the object inside.
4505  * If the callback is not defined the object will be destroyed with evas_object_del()
4506  *
4507  * @param clas the group class
4508  * @param del the callback to delete the content
4509  *
4510  * @ingroup Map
4511  */
4512 EAPI void
4513 elm_map_marker_class_del_cb_set(Elm_Map_Marker_Class *clas, ElmMapMarkerDelFunc del)
4514 {
4515    EINA_SAFETY_ON_NULL_RETURN(clas);
4516    clas->func.del = del;
4517 }
4518
4519 /**
4520  * Get the list of the sources.
4521  *
4522  * @param obj The map object
4523  * @return sources the source list
4524  *
4525  * @ingroup Map
4526  */
4527
4528 EAPI const char **
4529 elm_map_source_names_get(const Evas_Object *obj)
4530 {
4531    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4532    Widget_Data *wd = elm_widget_data_get(obj);
4533
4534    if (!wd) return NULL;
4535    return wd->source_names;
4536 }
4537
4538 /**
4539  * Set the source of the map.
4540  *
4541  * Elm_Map retrieves the image which composed the map from a web service. This web service can
4542  * be set with this method. A different service can return a different maps with different
4543  * information and it can use different zoom value.
4544  *
4545  * @param obj the map object
4546  * @param source the new source
4547  *
4548  * @ingroup Map
4549  */
4550 EAPI void
4551 elm_map_source_name_set(Evas_Object *obj, const char *source_name)
4552 {
4553    ELM_CHECK_WIDTYPE(obj, widtype);
4554    Widget_Data *wd = elm_widget_data_get(obj);
4555    Map_Sources_Tab *s = NULL, *ss;
4556    Eina_List *l;
4557    Grid *grid;
4558    int zoom;
4559
4560    if (!wd) return;
4561    if (!strcmp(wd->source_name, source_name)) return;
4562    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4563      {
4564         if (!strcmp(ss->name, wd->source_name))
4565           {
4566              s = ss;
4567              break;
4568           }
4569      }
4570    if (!s) return;
4571
4572    if (!s->url_cb) return;
4573
4574    EINA_LIST_FREE(wd->grids, grid) grid_clear(obj, grid);
4575
4576    eina_stringshare_replace(&wd->source_name, source_name);
4577    zoom = wd->zoom;
4578    wd->zoom = -1;
4579
4580    if (s->zoom_max < zoom)
4581      zoom = s->zoom_max;
4582    if (s->zoom_min > zoom)
4583      zoom = s->zoom_min;
4584
4585    elm_map_zoom_set(obj, zoom);
4586 }
4587
4588 /**
4589  * Get the name of a source.
4590  *
4591  * @param source the source
4592  * @return Returns the name of the source
4593  *
4594  * @ingroup Map
4595  */
4596 EAPI const char *
4597 elm_map_source_name_get(const Evas_Object *obj)
4598 {
4599    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4600    Widget_Data *wd = elm_widget_data_get(obj);
4601    Map_Sources_Tab *s = NULL, *ss;
4602    Eina_List *l;
4603
4604    if (!wd) return NULL;
4605    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4606      {
4607         if (!strcmp(ss->name, wd->source_name))
4608           {
4609              s = ss;
4610              break;
4611           }
4612      }
4613    if (!s) return NULL;
4614
4615    return s->name;
4616 }
4617
4618 /**
4619  * Set the source of the route.
4620  *
4621  * @param clas the group class
4622  * @param source the new source
4623  *
4624  * @ingroup Map
4625  */
4626 EAPI void
4627 elm_map_route_source_name_set(Evas_Object *obj, char *source_name)
4628 {
4629    ELM_CHECK_WIDTYPE(obj, widtype);
4630    Widget_Data *wd = elm_widget_data_get(obj);
4631
4632    if (!wd) return;
4633    eina_stringshare_replace(&wd->source_name, source_name);
4634 }
4635
4636 /**
4637  * Get the current route source
4638  *
4639  * @param obj the map object
4640  * @return Returns the source of the route
4641  *
4642  * @ingroup Map
4643  */
4644 EAPI Elm_Map_Route_Sources
4645 elm_map_route_source_get(const Evas_Object *obj)
4646 {
4647    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_ROUTE_SOURCE_YOURS;
4648    Widget_Data *wd = elm_widget_data_get(obj);
4649
4650    if (!wd) return ELM_MAP_ROUTE_SOURCE_YOURS;
4651    return wd->route_source;
4652 }
4653
4654 /**
4655  * Get the maximum zoom of the source.
4656  *
4657  * @param source the source
4658  * @return Returns the maximum zoom of the source
4659  *
4660  * @ingroup Map
4661  */
4662 EAPI int
4663 elm_map_source_zoom_max_get(const Evas_Object *obj)
4664 {
4665    ELM_CHECK_WIDTYPE(obj, widtype) 18;
4666    Widget_Data *wd = elm_widget_data_get(obj);
4667    Map_Sources_Tab *s = NULL, *ss;
4668    Eina_List *l;
4669
4670    if (!wd) return 18;
4671    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4672      {
4673         if (!strcmp(ss->name, wd->source_name))
4674           {
4675              s = ss;
4676              break;
4677           }
4678      }
4679    if (!s) return 0;
4680
4681    return s->zoom_max;
4682 }
4683
4684 /**
4685  * Get the minimum zoom of the source.
4686  *
4687  * @param source the source
4688  * @return Returns the minimum zoom of the source
4689  *
4690  * @ingroup Map
4691  */
4692 EAPI int
4693 elm_map_source_zoom_min_get(const Evas_Object *obj)
4694 {
4695    ELM_CHECK_WIDTYPE(obj, widtype) 0;
4696    Widget_Data *wd = elm_widget_data_get(obj);
4697    Map_Sources_Tab *s = NULL, *ss;
4698    Eina_List *l;
4699
4700    if (!wd) return 0;
4701    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4702      {
4703         if (!strcmp(ss->name, wd->source_name))
4704           {
4705              s = ss;
4706              break;
4707           }
4708      }
4709    if (!s) return 0;
4710
4711    return s->zoom_min;
4712 }
4713
4714 /**
4715  * Set the user agent of the widget map.
4716  *
4717  * @param obj The map object
4718  * @param user_agent the user agent of the widget map
4719  *
4720  * @ingroup Map
4721  */
4722 EAPI void
4723 elm_map_user_agent_set(Evas_Object *obj, const char *user_agent)
4724 {
4725    ELM_CHECK_WIDTYPE(obj, widtype);
4726    Widget_Data *wd = elm_widget_data_get(obj);
4727
4728    if (!wd) return;
4729    if (!wd->user_agent) wd->user_agent = eina_stringshare_add(user_agent);
4730    else eina_stringshare_replace(&wd->user_agent, user_agent);
4731
4732    if (!wd->ua) wd->ua = eina_hash_string_small_new(NULL);
4733    eina_hash_set(wd->ua, "User-Agent", wd->user_agent);
4734 }
4735
4736 /**
4737  * Get the user agent of the widget map.
4738  *
4739  * @param obj The map object
4740  * @return The user agent of the widget map
4741  *
4742  * @ingroup Map
4743  */
4744 EAPI const char *
4745 elm_map_user_agent_get(const Evas_Object *obj)
4746 {
4747    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4748    Widget_Data *wd = elm_widget_data_get(obj);
4749
4750    if (!wd) return NULL;
4751    return wd->user_agent;
4752 }
4753
4754 /**
4755  * Add a route on the map
4756  *
4757  * @param obj The map object
4758  * @param type the type if transport
4759  * @param method the routing method
4760  * @param flon the start longitude
4761  * @param flat the start latitude
4762  * @param tlon the destination longitude
4763  * @param tlat the destination latitude
4764  *
4765  * @return The Route object
4766  *
4767  * @ingroup Map
4768  */
4769 EAPI Elm_Map_Route *
4770 elm_map_route_add(Evas_Object *obj,
4771                   Elm_Map_Route_Type type,
4772                   Elm_Map_Route_Method method,
4773                   double flon,
4774                   double flat,
4775                   double tlon,
4776                   double tlat)
4777 {
4778    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4779    Widget_Data *wd = elm_widget_data_get(obj);
4780    Map_Sources_Tab *s = NULL, *ss;
4781    Eina_List *l;
4782    char buf[PATH_MAX];
4783    char *source;
4784    char *type_name = NULL;
4785    int fd;
4786
4787    if (!wd) return NULL;
4788    EINA_LIST_FOREACH(wd->map_sources_tab, l, ss)
4789      {
4790         if (!strcmp(ss->name, wd->source_name))
4791           {
4792              s = ss;
4793              break;
4794           }
4795      }
4796    if (!s) return NULL;
4797
4798    Elm_Map_Route *route = ELM_NEW(Elm_Map_Route);
4799    if (!route) return NULL;
4800
4801    snprintf(buf, sizeof(buf), DEST_ROUTE_XML_FILE);
4802    fd = mkstemp(buf);
4803    if (fd < 0)
4804      {
4805         free(route);
4806         return NULL;
4807      }
4808
4809    route->con_url = ecore_con_url_new(NULL);
4810    route->ud.fname = strdup(buf);
4811    INF("xml file : %s", route->ud.fname);
4812
4813    route->ud.fd = fdopen(fd, "w+");
4814    if ((!route->con_url) || (!route->ud.fd))
4815      {
4816         ecore_con_url_free(route->con_url);
4817         free(route);
4818         return NULL;
4819      }
4820
4821    route->wd = wd;
4822    route->color.r = 255;
4823    route->color.g = 0;
4824    route->color.b = 0;
4825    route->color.a = 255;
4826    route->handlers = eina_list_append
4827      (route->handlers, (void *)ecore_event_handler_add
4828          (ECORE_CON_EVENT_URL_COMPLETE, _route_complete_cb, route));
4829
4830    route->inbound = EINA_FALSE;
4831    route->type = type;
4832    route->method = method;
4833    route->flon = flon;
4834    route->flat = flat;
4835    route->tlon = tlon;
4836    route->tlat = tlat;
4837
4838    switch (type)
4839      {
4840       case ELM_MAP_ROUTE_TYPE_MOTOCAR:
4841         type_name = strdup(ROUTE_TYPE_MOTORCAR);
4842         break;
4843       case ELM_MAP_ROUTE_TYPE_BICYCLE:
4844         type_name = strdup(ROUTE_TYPE_BICYCLE);
4845         break;
4846       case ELM_MAP_ROUTE_TYPE_FOOT:
4847         type_name = strdup(ROUTE_TYPE_FOOT);
4848         break;
4849       default:
4850         break;
4851      }
4852
4853    source = s->route_url_cb(obj, type_name, method, flon, flat, tlon, tlat);
4854    INF("route url = %s", source);
4855
4856    wd->route = eina_list_append(wd->route, route);
4857
4858    ecore_con_url_url_set(route->con_url, source);
4859    ecore_con_url_fd_set(route->con_url, fileno(route->ud.fd));
4860    ecore_con_url_data_set(route->con_url, route);
4861    ecore_con_url_get(route->con_url);
4862    if (type_name) free(type_name);
4863    if (source) free(source);
4864
4865    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
4866                            "elm,state,busy,start", "elm");
4867    evas_object_smart_callback_call(wd->obj, SIG_ROUTE_LOAD, NULL);
4868    return route;
4869 }
4870
4871 /**
4872  * Remove a route from the map
4873  *
4874  * @param route The route to remove
4875  *
4876  * @ingroup Map
4877  */
4878
4879 EAPI void
4880 elm_map_route_remove(Elm_Map_Route *route)
4881 {
4882    EINA_SAFETY_ON_NULL_RETURN(route);
4883
4884    Route_Waypoint *w;
4885    Route_Node *n;
4886    Evas_Object *p;
4887    Ecore_Event_Handler *h;
4888
4889    EINA_LIST_FREE(route->path, p)
4890      {
4891         evas_object_del(p);
4892      }
4893
4894    EINA_LIST_FREE(route->waypoint, w)
4895      {
4896         if (w->point) eina_stringshare_del(w->point);
4897         free(w);
4898      }
4899
4900    EINA_LIST_FREE(route->nodes, n)
4901      {
4902         if (n->pos.address) eina_stringshare_del(n->pos.address);
4903         free(n);
4904      }
4905
4906    EINA_LIST_FREE(route->handlers, h)
4907      {
4908         ecore_event_handler_del(h);
4909      }
4910
4911    if (route->ud.fname)
4912      {
4913         ecore_file_remove(route->ud.fname);
4914         free(route->ud.fname);
4915         route->ud.fname = NULL;
4916      }
4917 }
4918
4919 /**
4920  * Set the option used for the background color
4921  *
4922  * @param route The route object
4923  * @param r
4924  * @param g
4925  * @param b
4926  * @param a
4927  *
4928  * This sets the color used for the route
4929  *
4930  * @ingroup Map
4931  */
4932 EAPI void
4933 elm_map_route_color_set(Elm_Map_Route *route, int r, int g , int b, int a)
4934 {
4935    EINA_SAFETY_ON_NULL_RETURN(route);
4936    route->color.r = r;
4937    route->color.g = g;
4938    route->color.b = b;
4939    route->color.a = a;
4940 }
4941
4942 /**
4943  * Get the option used for the background color
4944  *
4945  * @param route The route object
4946  * @param r
4947  * @param g
4948  * @param b
4949  * @param a
4950  *
4951  * @ingroup Map
4952  */
4953 EAPI void
4954 elm_map_route_color_get(const Elm_Map_Route *route, int *r, int *g , int *b, int *a)
4955 {
4956    EINA_SAFETY_ON_NULL_RETURN(route);
4957    if (r) *r = route->color.r;
4958    if (g) *g = route->color.g;
4959    if (b) *b = route->color.b;
4960    if (a) *a = route->color.a;
4961 }
4962
4963 /**
4964  * Get the information of route distance
4965  *
4966  * @param route the route object
4967  * @return Returns the distance of route (unit : km)
4968  *
4969  * @ingroup Map
4970  */
4971 EAPI double
4972 elm_map_route_distance_get(const Elm_Map_Route *route)
4973 {
4974    EINA_SAFETY_ON_NULL_RETURN_VAL(route, 0.0);
4975    return route->info.distance;
4976 }
4977
4978 /**
4979  * Get the information of route nodes
4980  *
4981  * @param route the route object
4982  * @return Returns the nodes of route
4983  *
4984  * @ingroup Map
4985  */
4986
4987 EAPI const char*
4988 elm_map_route_node_get(const Elm_Map_Route *route)
4989 {
4990    EINA_SAFETY_ON_NULL_RETURN_VAL(route, NULL);
4991    return route->info.nodes;
4992 }
4993
4994 /**
4995  * Get the information of route waypoint
4996  *
4997  * @param route the route object
4998  * @return Returns the waypoint of route
4999  *
5000  * @ingroup Map
5001  */
5002
5003 EAPI const char*
5004 elm_map_route_waypoint_get(const Elm_Map_Route *route)
5005 {
5006    EINA_SAFETY_ON_NULL_RETURN_VAL(route, NULL);
5007    return route->info.waypoints;
5008 }
5009
5010 /**
5011  * Get the information of address
5012  *
5013  * @param name the name object
5014  * @return Returns the address of name
5015  *
5016  * @ingroup Map
5017  */
5018 EAPI const char *
5019 elm_map_name_address_get(const Elm_Map_Name *name)
5020 {
5021    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
5022    return name->address;
5023 }
5024
5025 /**
5026  * Get the current coordinates of the name.
5027  *
5028  * This gets the current coordinates of the name object.
5029  *
5030  * @param obj The name object
5031  * @param lat The latitude
5032  * @param lon The longitude
5033  *
5034  * @ingroup Map
5035  */
5036 EAPI void
5037 elm_map_name_region_get(const Elm_Map_Name *name, double *lon, double *lat)
5038 {
5039    EINA_SAFETY_ON_NULL_RETURN(name);
5040    if (lon) *lon = name->lon;
5041    if (lat) *lat = name->lat;
5042 }
5043
5044 /**
5045  * Remove a name from the map
5046  *
5047  * @param name The name to remove
5048  *
5049  * @ingroup Map
5050  */
5051 EAPI void
5052 elm_map_name_remove(Elm_Map_Name *name)
5053 {
5054    EINA_SAFETY_ON_NULL_RETURN(name);
5055    if (name->address)
5056      {
5057         free(name->address);
5058         name->address = NULL;
5059      }
5060    if (name->handler)
5061      {
5062         ecore_event_handler_del(name->handler);
5063         name->handler = NULL;
5064      }
5065    if (name->ud.fname)
5066      {
5067         ecore_file_remove(name->ud.fname);
5068         free(name->ud.fname);
5069         name->ud.fname = NULL;
5070      }
5071 }
5072
5073 /**
5074  * Set the rotate degree of the map
5075  *
5076  * @param obj The map object
5077  * @param angle amount of degrees from 0.0 to 360.0 to rotate arount Z axis
5078  * @param cx rotation's center horizontal position
5079  * @param cy rotation's center vertical position
5080  *
5081  * @ingroup Map
5082  */
5083 EAPI void
5084 elm_map_rotate_set(Evas_Object *obj, double degree, Evas_Coord cx, Evas_Coord cy)
5085 {
5086    ELM_CHECK_WIDTYPE(obj, widtype);
5087    Widget_Data *wd = elm_widget_data_get(obj);
5088
5089    if (!wd) return;
5090    wd->rotate.d = degree;
5091    wd->rotate.cx = cx;
5092    wd->rotate.cy = cy;
5093    wd->calc_job = ecore_job_add(_calc_job, wd);
5094 }
5095
5096 /**
5097  * Get the rotate degree of the map
5098  *
5099  * @param obj The map object
5100  * @return amount of degrees from 0.0 to 360.0 to rotate arount Z axis
5101  * @param cx rotation's center horizontal position
5102  * @param cy rotation's center vertical position
5103  *
5104  * @ingroup Map
5105  */
5106 EAPI void
5107 elm_map_rotate_get(const Evas_Object *obj, double *degree, Evas_Coord *cx, Evas_Coord *cy)
5108 {
5109    ELM_CHECK_WIDTYPE(obj, widtype);
5110    Widget_Data *wd = elm_widget_data_get(obj);
5111
5112    if (!wd) return;
5113    if (degree) *degree = wd->rotate.d;
5114    if (cx) *cx = wd->rotate.cx;
5115    if (cy) *cy = wd->rotate.cy;
5116 }
5117
5118 /**
5119  * Set the wheel control state of the map
5120  *
5121  * @param obj The map object
5122  * @param disabled status of wheel control
5123  *
5124  * @ingroup Map
5125  */
5126 EAPI void
5127 elm_map_wheel_disabled_set(Evas_Object *obj, Eina_Bool disabled)
5128 {
5129    ELM_CHECK_WIDTYPE(obj, widtype);
5130    Widget_Data *wd = elm_widget_data_get(obj);
5131
5132    if (!wd) return;
5133    if ((!wd->wheel_disabled) && (disabled))
5134      evas_object_event_callback_del_full(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
5135    else if ((wd->wheel_disabled) && (!disabled))
5136      evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
5137    wd->wheel_disabled = !!disabled;
5138 }
5139
5140 /**
5141  * Get the wheel control state of the map
5142  *
5143  * @param obj The map object
5144  * @return Returns the status of wheel control
5145  *
5146  * @ingroup Map
5147  */
5148 EAPI Eina_Bool
5149 elm_map_wheel_disabled_get(const Evas_Object *obj)
5150 {
5151    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
5152    Widget_Data *wd = elm_widget_data_get(obj);
5153
5154    if (!wd) return EINA_FALSE;
5155    return wd->wheel_disabled;
5156 }
5157
5158 static char *
5159 _mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
5160 {
5161    char buf[PATH_MAX];
5162    snprintf(buf, sizeof(buf), "http://tile.openstreetmap.org/%d/%d/%d.png",
5163             zoom, x, y);
5164    return strdup(buf);
5165 }
5166
5167 static char *
5168 _osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
5169 {
5170    char buf[PATH_MAX];
5171    snprintf(buf, sizeof(buf),
5172             "http://tah.openstreetmap.org/Tiles/tile/%d/%d/%d.png",
5173             zoom, x, y);
5174    return strdup(buf);
5175 }
5176
5177 static char *
5178 _cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
5179 {
5180    char buf[PATH_MAX];
5181    snprintf(buf, sizeof(buf),
5182             "http://andy.sandbox.cloudmade.com/tiles/cycle/%d/%d/%d.png",
5183             zoom, x, y);
5184    return strdup(buf);
5185 }
5186
5187 static char *
5188 _maplint_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
5189 {
5190    char buf[PATH_MAX];
5191    snprintf(buf, sizeof(buf),
5192             "http://tah.openstreetmap.org/Tiles/maplint/%d/%d/%d.png",
5193             zoom, x, y);
5194    return strdup(buf);
5195 }
5196
5197 static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
5198 {
5199    char buf[PATH_MAX];
5200    snprintf(buf, sizeof(buf),
5201             "%s?flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&v=%s&fast=%d&instructions=1",
5202             ROUTE_YOURS_URL, flat, flon, tlat, tlon, type_name, method);
5203
5204    return strdup(buf);
5205 }
5206
5207 // TODO: fix monav api
5208 /*
5209 static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
5210 {
5211    char buf[PATH_MAX];
5212    snprintf(buf, sizeof(buf),
5213             "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
5214             ROUTE_MONAV_URL, flat, flon, tlat, tlon, type_name, method);
5215
5216    return strdup(buf);
5217 }
5218 */
5219
5220 // TODO: fix ors api
5221 /*
5222 static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
5223 {
5224    char buf[PATH_MAX];
5225    snprintf(buf, sizeof(buf),
5226             "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
5227             ROUTE_ORS_URL, flat, flon, tlat, tlon, type_name, method);
5228
5229    return strdup(buf);
5230 }
5231 */
5232
5233 static char *
5234 _nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat)
5235 {
5236    ELM_CHECK_WIDTYPE(obj, widtype) strdup("");
5237    Widget_Data *wd = elm_widget_data_get(obj);
5238    char **str;
5239    unsigned int ele, idx;
5240    char search_url[PATH_MAX];
5241    char buf[PATH_MAX];
5242
5243    if (!wd) return strdup("");
5244    if (method == ELM_MAP_NAME_METHOD_SEARCH)
5245      {
5246         search_url[0] = '\0';
5247         str = eina_str_split_full(name, " ", 0, &ele);
5248         for (idx = 0 ; idx < ele ; idx++)
5249           {
5250              eina_strlcat(search_url, str[idx], sizeof(search_url));
5251              if (!(idx == (ele-1))) eina_strlcat(search_url, "+", sizeof(search_url));
5252           }
5253         snprintf(buf, sizeof(buf), "%s/search?q=%s&format=xml&polygon=0&addressdetails=0", NAME_NOMINATIM_URL, search_url);
5254      }
5255    else if (method == ELM_MAP_NAME_METHOD_REVERSE) snprintf(buf, sizeof(buf), "%s/reverse?format=xml&lat=%lf&lon=%lf&zoom=%d&addressdetails=0", NAME_NOMINATIM_URL, lat, lon, wd->zoom);
5256    else strcpy(buf, "");
5257
5258    return strdup(buf);
5259 }
5260