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