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