From: Bluezery <ohpowel@gmail.com>
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 21 Feb 2012 08:01:22 +0000 (08:01 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 21 Feb 2012 08:01:22 +0000 (08:01 +0000)
Subject: [E-devel] [Patch][elm_map] Refactoring Elementary Map

I have done refactoring & code clean-up in elm_map.  Event if this
patch have much changes, refactoring & code clean-up jobs almost
always do.
Anyway, code is shortened and optimized I think.
 I have done following jobs in my patch.

 (1) Always change child size
 Scroller Child size is changed when integer zoom level is changed
 before. This makes bugs which mouse pointer is not correct on the map
 when map is dragging.
 Now, scroller child size is always changed when double zoom level is
changed.

(2) Evas map
Evas map is used for rotation & zooming before. But now it is used for
only rotation. evas_object_resize() can do zooming because (1) makes
child size always changed.

(3) Grid & Marker & Route, etc.
Because of (1), all coordinate calculations are all changed. So grid &
marker & route should be changed.
When I have fixed these, I have these split into small function
(create, free, update, place, etc.)
So these can be easily reused for other purpose ( I will add overlay
later.)
Also marker size is not changed and is not rotated anymore because
marker's coordinate is just rotated and evas_map is not used for
marker.

And grouping algorithm is somewhat changed. Each marker can be group
leader and if other markers (followers) are closed to leader, markers
are grouped.

Actually _marker_place() function do almost everything. (place marker,
bubble, group & make group, etc.)

Bubbles go along with parent object. (show, hide, move) and this is
created when marker & group are opened.
At now, bubble display bugs are all fixed.

As before, grid is created when elm_map_add() or tile source is
changed. And I add _grid_item_* functions for each 256x256 tile
management.  So grid_place() function can be simple now.

(4) Download idler
Before download is not a job or idler and is integrated with grid
calculation.
I have separated this into independent idler. So now, download idler
do download jobs when idler time.

(5) Zoom
I have made one zoom_do() function.  This does all zoom jobs. At now,
pinch_zoom & wheel_zoom & animated zoom do not much jobs. just call
zoom_do().

(6) Delayed jobs
As I know, evas is based on a retained mode and calculation can be do
later. So sometimes elm_map APIs can not  do the jobs correctly.
For example, elm_map_marker_list_show() or elm_map_zoom_set() can not
be used right after elm_map_add()  because window size and pan size
can be 0.   (refer map_example_02.c)
So when APIs related such calculation are called. These are deferred
and calculated later when _pan_calculate() is called.

5) Code clean-up
I have removed unused variables & functions.  and rearranged struct &
functions & declaration & static variables, etc.
Instead of "if (!wd) return; ", I changed this by macro,
"EINA_SAFETY_ON_NULL_RETURN(wd);". This is better for function
entrance check. Also ELM_NEW is used instead of calloc or malloc.

Aboves are all related each other. So it can be hard to split this
file. If these should be splitted, I'm going to freak ;D.
This patch does no harm!!!! :D.
 After this patch, I will add overlay APIs based on this patch.  I
 doubt whether I will add this before elementary 1.0 release.  :(

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@68207 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/test_map.c
src/examples/map_example_02.c
src/lib/elm_map.c

index 7f2da19..8600469 100644 (file)
@@ -20,10 +20,9 @@ typedef struct Map_Source
 } Map_Source;
 
 static Elm_Map_Marker_Class *itc1, *itc2, *itc_parking;
-static Elm_Map_Group_Class *itc_group1, *itc_group2, *itc_group_parking;
+static Elm_Map_Group_Class *itc_group1, *itc_group2, *itc_group_parking, *route_group;
 
-static Evas_Object *rect, *menu, *fs_win;
-static int nb_elts;
+static Evas_Object *menu, *fs_win;
 /*static Elm_Map_Marker *markers[MARKER_MAX];*/
 static Elm_Map_Marker *route_from, *route_to;
 static Elm_Map_Route *route;
@@ -88,14 +87,14 @@ my_map_press(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_inf
 static void
 my_map_longpressed(void *data __UNUSED__, Evas_Object *obj, void *event_info)
 {
-   printf("longpressed\n");
+   if (!event_info) return;
    double lon, lat;
    Evas_Event_Mouse_Down *down = (Evas_Event_Mouse_Down *)event_info;
-   if (!down) return;
-   if (elm_map_zoom_get(obj) < 5) return;
-
    elm_map_canvas_to_geo_convert(obj, down->canvas.x, down->canvas.y, &lon, &lat);
-   printf("x:%d, y:%d, lon:%lf, lat:%lf\n", down->canvas.x, down->canvas.y, lon, lat);
+   printf("longpressed, x:%d, y:%d, lon:%lf, lat:%lf\n", down->canvas.x, down->canvas.y, lon, lat);
+
+   if (elm_map_zoom_get(obj) < 5) return;
+   if (name) elm_map_name_remove(name);
    name = elm_map_utils_convert_coord_into_name(obj, lon, lat);
 }
 
@@ -111,15 +110,18 @@ my_map_clicked_double(void *data __UNUSED__, Evas_Object *obj, void *event_info)
 
    elm_map_canvas_to_geo_convert(obj, down->canvas.x, down->canvas.y, &lon, &lat);
    printf("x:%d, y:%d, lon:%lf, lat:%lf\n", down->canvas.x, down->canvas.y, lon, lat);
-   itc1 = elm_map_marker_class_new(obj);
+   if (!itc1) itc1 = elm_map_marker_class_new(obj);
 
    elm_map_marker_class_del_cb_set(itc1, NULL);
 
-   itc_group1 = elm_map_group_class_new(obj);
-   elm_map_group_class_icon_cb_set(itc_group1, _group_icon_get);
-   elm_map_group_class_data_set(itc_group1, (void *)PACKAGE_DATA_DIR"/images/bubble.png");
-   elm_map_group_class_style_set(itc_group1, "empty");
-   elm_map_group_class_zoom_displayed_set(itc_group1, 5);
+   if (!route_group)
+     {
+        route_group = elm_map_group_class_new(obj);
+        elm_map_group_class_icon_cb_set(route_group, _group_icon_get);
+        elm_map_group_class_data_set(route_group, (void *)PACKAGE_DATA_DIR"/images/bubble.png");
+        elm_map_group_class_style_set(route_group, "empty");
+        elm_map_group_class_zoom_displayed_set(route_group, 5);
+     }
 
    if (route_from && route_to)
      {
@@ -130,8 +132,8 @@ my_map_clicked_double(void *data __UNUSED__, Evas_Object *obj, void *event_info)
         elm_map_route_remove(route);
      }
 
-   if (!route_from) route_from = elm_map_marker_add(obj, lon, lat, itc1, itc_group1, NULL);
-   else route_to = elm_map_marker_add(obj, lon, lat, itc1, itc_group1, NULL);
+   if (!route_from) route_from = elm_map_marker_add(obj, lon, lat, itc1, route_group, NULL);
+   else route_to = elm_map_marker_add(obj, lon, lat, itc1, route_group, NULL);
 
    if (route_from && route_to)
      {
@@ -201,10 +203,9 @@ my_map_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNU
 static void
 my_map_scroll(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
 {
-   printf("scroll\n");
    double lon, lat;
    elm_map_geo_region_get(obj, &lon, &lat);
-   printf("scroll longitude : %f latitude : %f\n", lon, lat);
+   printf("scroll, longitude: %f latitude: %f\n", lon, lat);
 }
 
 static void
@@ -582,16 +583,6 @@ _group_icon_get(Evas_Object *obj, void *data)
 }
 
 static void
-_map_move_resize_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
-{
-   int x,y,w,h;
-
-   evas_object_geometry_get(data,&x,&y,&w,&h);
-   evas_object_resize(rect,w,h);
-   evas_object_move(rect,x,y);
-}
-
-static void
 _populate(void *data, Elm_Object_Item *menu_it)
 {
    int idx;
@@ -729,7 +720,6 @@ test_map(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __
         elm_win_resize_object_add(win, map);
         evas_object_data_set(map, "window", win);
 
-        //
         itc1 = elm_map_marker_class_new(map);
         elm_map_marker_class_get_cb_set(itc1, _marker_get);
         elm_map_marker_class_del_cb_set(itc1, NULL);
@@ -744,9 +734,7 @@ test_map(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __
         elm_map_marker_class_del_cb_set(itc_parking, NULL);
         elm_map_marker_class_icon_cb_set(itc_parking, _icon_get);
         elm_map_marker_class_style_set(itc_parking, "empty");
-        //
 
-        //
         itc_group1 = elm_map_group_class_new(map);
         elm_map_group_class_data_set(itc_group1, (void *)PACKAGE_DATA_DIR"/images/plant_01.jpg");
 
@@ -759,18 +747,7 @@ test_map(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __
         elm_map_group_class_data_set(itc_group_parking, (void *)PACKAGE_DATA_DIR"/images/parking.png");
         elm_map_group_class_style_set(itc_group_parking, "empty");
         elm_map_group_class_zoom_displayed_set(itc_group_parking, 5);
-        //
-
-        rect = evas_object_rectangle_add(evas_object_evas_get(win));
-        evas_object_color_set(rect, 0, 0, 0, 0);
-        evas_object_repeat_events_set(rect,1);
-        evas_object_show(rect);
-        evas_object_raise(rect);
-
-        evas_object_event_callback_add(map, EVAS_CALLBACK_RESIZE,
-                                       _map_move_resize_cb, map);
-        evas_object_event_callback_add(map, EVAS_CALLBACK_MOVE,
-                                       _map_move_resize_cb, map);
+
         evas_object_event_callback_add(map, EVAS_CALLBACK_MOUSE_DOWN,
                                        _map_mouse_down, map);
         evas_object_event_callback_add(map, EVAS_CALLBACK_MOUSE_MOVE,
@@ -793,8 +770,6 @@ test_map(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __
         elm_map_marker_add(map, 7.3165409990833, 48.856078, itc2, itc_group1, &data11);
         elm_map_marker_add(map, 7.319812, 48.856561, itc2, itc_group2, &data10);
 
-        nb_elts = 13;
-
         evas_object_smart_callback_add(map, "clicked", my_map_clicked, map);
         evas_object_smart_callback_add(map, "press", my_map_press, map);
         evas_object_smart_callback_add(map, "longpressed", my_map_longpressed, map);
index 7557f20..0a8a8c0 100644 (file)
@@ -94,13 +94,6 @@ _group_country_content_get(Evas_Object *obj, void *data __UNUSED__)
 }
 
 static void
-_map_downloaded(void *data __UNUSED__, Evas_Object *obj, void *ev __UNUSED__)
-{
-   elm_map_zoom_set(obj, 3);
-   evas_object_smart_callback_del(obj, "downloaded", _map_downloaded);
-}
-
-static void
 _bt_zoom_in(void *data, Evas_Object *obj __UNUSED__, void *ev __UNUSED__)
 {
    Evas_Object *map = data;
@@ -241,7 +234,6 @@ elm_main(int argc __UNUSED__, char **argv __UNUSED__)
    markers = eina_list_append(markers, m);
 
    elm_map_markers_list_show(markers);
-   evas_object_smart_callback_add(map, "downloaded", _map_downloaded, NULL);
 
    evas_object_resize(win, 512, 512);
    evas_object_show(win);
index d9adef9..8c4733b 100644 (file)
@@ -13,14 +13,20 @@ typedef struct _Pan Pan;
 typedef struct _Grid Grid;
 typedef struct _Grid_Item Grid_Item;
 typedef struct _Marker_Group Marker_Group;
-typedef struct _Event Event;
+typedef struct _Marker_Bubble Marker_Bubble;
 typedef struct _Path_Node Path_Node;
 typedef struct _Path_Waypoint Path_Waypoint;
 typedef struct _Url_Data Url_Data;
 typedef struct _Route_Dump Route_Dump;
 typedef struct _Name_Dump Name_Dump;
 typedef struct _Track_Dump Track_Dump;
+typedef struct _Delayed_Data Delayed_Data;
+typedef struct _Map_Sources_Tab Map_Sources_Tab;
 
+#define ROUND(z) (((z) < 0) ? (int)ceil((z) - 0.005) : (int)floor((z) + 0.005))
+#define EVAS_MAP_POINT 4
+#define DEFAULT_TILE_SIZE 256
+#define MARER_MAX_NUMBER 30
 #define CACHE_ROOT_PATH   "/tmp/elm_map"
 #define CACHE_PATH        CACHE_ROOT_PATH"/%d/%d/%d"
 #define CACHE_FILE_PATH   "%s/%d.png"
@@ -35,31 +41,62 @@ typedef struct _Track_Dump Track_Dump;
 #define YOURS_DESCRIPTION "description"
 #define YOURS_COORDINATES "coordinates"
 
-// TODO: fix monav & ors url
-#define ROUTE_MONAV_URL "http://"
-#define ROUTE_ORS_URL "http:///"
-
 #define NAME_NOMINATIM_URL "http://nominatim.openstreetmap.org"
 #define NOMINATIM_RESULT "result"
 #define NOMINATIM_PLACE "place"
 #define NOMINATIM_ATTR_LON "lon"
 #define NOMINATIM_ATTR_LAT "lat"
 
-#define PINCH_ZOOM_MIN 0.25
-#define PINCH_ZOOM_MAX 4.0
 #define MAX_CONCURRENT_DOWNLOAD 10
 
+/* FIXME: This is unused currently
 #define GPX_NAME "name>"
 #define GPX_COORDINATES "trkpt "
 #define GPX_LON "lon"
 #define GPX_LAT "lat"
 #define GPX_ELE "ele>"
 #define GPX_TIME "time>"
+*/
+
+enum _Route_Xml_Attribute
+{
+   ROUTE_XML_NONE,
+   ROUTE_XML_DISTANCE,
+   ROUTE_XML_DESCRIPTION,
+   ROUTE_XML_COORDINATES,
+   ROUTE_XML_LAST
+} Route_Xml_Attibute;
+
+enum _Name_Xml_Attribute
+{
+   NAME_XML_NONE,
+   NAME_XML_NAME,
+   NAME_XML_LON,
+   NAME_XML_LAT,
+   NAME_XML_LAST
+} Name_Xml_Attibute;
+
+enum _Track_Xml_Attribute
+{
+   TRACK_XML_NONE,
+   TRACK_XML_COORDINATES,
+   TRACK_XML_LAST
+} Track_Xml_Attibute;
+
+struct _Delayed_Data
+{
+   void (*func)(void *data);
+   Widget_Data *wd;
+   Elm_Map_Zoom_Mode mode;
+   int zoom;
+   double lon, lat;
+   Eina_List *markers;
+};
 
 // Map sources
 // Currently the size of a tile must be 256*256
 // and the size of the map must be pow(2.0, z)*tile_size
-typedef struct _Map_Sources_Tab
+struct _Map_Sources_Tab
 {
    const char *name;
    int zoom_min;
@@ -70,29 +107,6 @@ typedef struct _Map_Sources_Tab
    ElmMapModuleNameUrlFunc name_url_cb;
    ElmMapModuleGeoIntoCoordFunc geo_into_coord;
    ElmMapModuleCoordIntoGeoFunc coord_into_geo;
-} Map_Sources_Tab;
-
-//Zemm min is supposed to be 0
-static char *_mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
-static char *_osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
-static char *_cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
-static char *_mapquest_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
-static char *_mapquest_aerial_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
-
-static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
-/*
-static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
-static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
- */
-static char *_nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat);
-
-static Map_Sources_Tab default_map_sources_tab[] =
-{
-     {"Mapnik", 0, 18, _mapnik_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
-     {"Osmarender", 0, 17, _osmarender_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
-     {"CycleMap", 0, 16, _cyclemap_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
-     {"MapQuest", 0, 18, _mapquest_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
-     {"MapQuest Open Aerial", 0, 11, _mapquest_aerial_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
 };
 
 struct _Url_Data
@@ -106,78 +120,68 @@ struct _Url_Data
 struct _Elm_Map_Marker_Class
 {
    const char *style;
-   int zoom_displayed;
-
    struct _Elm_Map_Marker_Class_Func
      {
         ElmMapMarkerGetFunc get;
         ElmMapMarkerDelFunc del; //if NULL the object will be destroyed with evas_object_del()
         ElmMapMarkerIconGetFunc icon_get;
      } func;
-
-   struct
-     { //this part is private, do not modify these values
-        Eina_Bool set : 1;
-        Evas_Coord edje_w, edje_h;
-     } priv;
 };
 
-struct _Elm_Map_Marker
+struct _Elm_Map_Group_Class
 {
    Widget_Data *wd;
-   Elm_Map_Marker_Class *clas;
-   Elm_Map_Group_Class *clas_group;
-   double longitude, latitude;
-
-   Evas_Coord map_size;
-   Evas_Coord *x, *y;
-   void *data;
-   Marker_Group **groups;
-   Evas_Object *content;
-};
 
-struct _Elm_Map_Group_Class
-{
+   Eina_List *markers;
+   int zoom_displayed; // display the group if the zoom is >= to zoom_display
+   int zoom_grouped;   // group the markers only if the zoom is <= to zoom_groups
    const char *style;
    void *data;
-   int zoom_displayed; // display the group if the zoom is >= to zoom_display
-   int zoom_grouped; // group the markers only if the zoom is <= to zoom_groups
-   Eina_Bool hide : 1;
-
    struct
      {
         ElmMapGroupIconGetFunc icon_get;
      } func;
 
-   struct
-     { //this part is private, do not modify these values
-        Eina_Bool set : 1;
-        Evas_Coord edje_w, edje_h;
-        Evas_Coord edje_max_w, edje_max_h;
-
-        Eina_List *objs_used;
-        Eina_List *objs_notused;
-     } priv;
+   Eina_Bool hide : 1;
+};
+
+struct _Marker_Bubble
+{
+   Widget_Data *wd;
+   Evas_Object *pobj;
+   Evas_Object *obj, *sc, *bx;
+};
+
+struct _Elm_Map_Marker
+{
+   Widget_Data *wd;
+   Elm_Map_Marker_Class *clas;
+   Elm_Map_Group_Class *group_clas;
+   double longitude, latitude;
+   Evas_Coord w, h;
+   Evas_Object *obj;
+
+   Evas_Coord x, y;
+   Eina_Bool grouped : 1;
+   Eina_Bool leader : 1; // if marker is group leader
+   Marker_Group *group;
+
+   Marker_Bubble *bubble;
+   Evas_Object *content;
+   void *data;
 };
 
 struct _Marker_Group
 {
    Widget_Data *wd;
-   Eina_Matrixsparse_Cell *cell;
    Elm_Map_Group_Class *clas;
+   Evas_Coord w, h;
+   Evas_Object *obj;
 
-   Eina_List *markers;
-   long long sum_x, sum_y;
    Evas_Coord x, y;
-   Evas_Coord w, h;
+   Eina_List *markers;
 
-   Evas_Object *obj, *bubble, *sc, *bx, *rect;
-   Eina_Bool open : 1;
-   Eina_Bool bringin : 1;
-   Eina_Bool update_nbelems : 1;
-   Eina_Bool update_resize : 1;
-   Eina_Bool update_raise : 1;
-   Eina_Bool delete_object : 1;
+   Marker_Bubble *bubble;
 };
 
 struct _Elm_Map_Route
@@ -250,218 +254,152 @@ struct _Elm_Map_Name
    Ecore_Event_Handler *handler;
 };
 
+struct _Route_Dump
+{
+   int id;
+   char *fname;
+   double distance;
+   char *description;
+   char *coordinates;
+};
+
+struct _Name_Dump
+{
+   int id;
+   char *address;
+   double lon;
+   double lat;
+};
+
 struct _Grid_Item
 {
-   Widget_Data *wd;
    Grid *g;
-   int zoom;
+
+   Widget_Data *wd;
    Evas_Object *img;
-   //Evas_Object *txt;
    const char *file;
    const char *source;
-   struct
-     {
-        int x, y, w, h;
-     } src, out;
-
+   int x, y;  // Tile coordinate
    Eina_Bool file_have : 1;
+
    Ecore_File_Download_Job *job;
-   int try_num;
 };
 
 struct _Grid
 {
    Widget_Data *wd;
-   int tsize; // size of tile (tsize x tsize pixels)
    int zoom; // zoom level tiles want for optimal display (1, 2, 4, 8)
-   int iw, ih; // size of image in pixels
-   int w, h; // size of grid image in pixels (represented by grid)
-   int gw, gh; // size of grid in tiles
+   int tw, th; // size of grid in tiles
    Eina_Matrixsparse *grid;
 };
 
+struct _Pan
+{
+   Evas_Object_Smart_Clipped_Data __clipped_data;
+   Widget_Data *wd;
+};
+
 struct _Widget_Data
 {
    Evas_Object *obj;
    Evas_Object *scr;
    Evas_Object *ges;
    Evas_Object *pan_smart;
-   Evas_Object *rect;
-   Evas_Object *sep_maps_markers; //map objects are below this object and marker objects are on top
-   Pan *pan;
-   Evas_Coord pan_x, pan_y, minw, minh;
+   Evas_Object *sep_maps_markers; // Tiles are below this and overlays are on top
+   Evas_Map *map;
+
+   Map_Sources_Tab *src;
+   Eina_List *srcs;
+   const char **src_names;
+   int zoom_min, zoom_max;
+   int tsize;
 
    int id;
-   int zoom;
-   int zoom_method;
-   Elm_Map_Zoom_Mode mode;
+   Eina_List *grids;
 
-   Ecore_Job *calc_job;
-   Ecore_Timer *scr_timer;
-   Ecore_Timer *long_timer;
-   Ecore_Animator *zoom_animator;
-   double t;
+   int zoom;
+   double zoom_detail;
+   double prev_lon, prev_lat;
+   Evas_Coord ox, oy;
    struct
      {
-        int w, h;
-        int ow, oh, nw, nh;
-        struct
-          {
-             double x, y;
-          } spos;
+        int w, h;  // Current pixel width, heigth of a grid
+        int tile;  // Current pixel size of a grid item
      } size;
+   Elm_Map_Zoom_Mode mode;
    struct
      {
-        Eina_Bool show : 1;
-        Evas_Coord x, y ,w ,h;
-     } show;
-   int tsize;
-   int nosmooth;
-   Eina_List *grids;
-   Eina_Bool resized : 1;
-   Eina_Bool on_hold : 1;
-   Eina_Bool paused : 1;
-   Eina_Bool paused_markers : 1;
-
-   struct
-     {
-        Eina_Bool enabled;
-        double lon, lat;
-     } center_on;
-
-   Ecore_Job *markers_place_job;
-   Eina_Matrixsparse **markers;
-   Eina_List *cells_displayed; // list of Eina_Matrixsparse_Cell
-   Evas_Coord markers_max_num;
-   int marker_max_w, marker_max_h;
-   int marker_zoom;
-   Eina_List *opened_bubbles; //opened bubbles, list of Map_Group *
-
-   Eina_List *groups_clas; // list of Elm_Map_Group_Class*
-   Eina_List *markers_clas; // list of Elm_Map_Markers_Class*
+        double zoom;
+        double diff;
+        int cnt;
+     } ani;
+   Ecore_Timer *zoom_timer;
+   Ecore_Animator *zoom_animator;
 
-   Elm_Map_Route_Sources route_source;
-   Eina_List *s_event_list;
    int try_num;
    int finish_num;
-
+   int download_num;
+   Eina_List *download_list;
+   Ecore_Idler *download_idler;
    Eina_Hash *ua;
    const char *user_agent;
-   Eina_List *route;
-   Eina_List *track;
-   Evas_Event_Mouse_Down ev;
-   Eina_List *names;
-   int multi_count;
 
-   struct
-     {
-        Evas_Coord cx, cy;
-        double level, diff;
-     } pinch;
+   Evas_Coord pan_x, pan_y;
+   Eina_List *delayed_jobs;
+
+   Ecore_Timer *scr_timer;
+   Ecore_Timer *long_timer;
+   Evas_Event_Mouse_Down ev;
+   Eina_Bool on_hold : 1;
+   Eina_Bool paused : 1;
 
+   double pinch_zoom;
    struct
      {
         Evas_Coord cx, cy;
         double a, d;
      } rotate;
 
-   int wheel_diff;
    Eina_Bool wheel_disabled : 1;
-   Eina_Bool scr_started : 1;
 
-   Eina_Array *modules;
-   Eina_List *map_sources_tab;
-   const char **source_names;
-   Evas_Map *map;
-   Ecore_Timer *zoom_timer;
-   Map_Sources_Tab *src;
-   const char *gpx_file;
-   int zoom_min, zoom_max;
-   Eina_List *download_list;
-   int download_num;
-};
+   unsigned int markers_max_num;
+   Eina_Bool paused_markers : 1;
+   Eina_List *group_classes;
+   Eina_List *marker_classes;
+   Eina_List *markers;
 
-struct _Pan
-{
-   Evas_Object_Smart_Clipped_Data __clipped_data;
-   Widget_Data *wd;
+   Elm_Map_Route_Sources route_source;
+   Eina_List *route;
+   Eina_List *track;
+   Eina_List *names;
 };
 
-struct _Event
-{
-   int device;
-
-   struct
-     {
-        Evas_Coord x, y;
-     } start;
-
-   struct
-     {
-        Evas_Coord x, y;
-     } prev;
-
-   Evas_Coord x, y, w, h;
-
-   Evas_Object *object;
-
-   int pinch_start_dis;
-   int pinch_dis;
-};
+static char *_mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
+static char *_osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
+static char *_cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
+static char *_mapquest_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
+static char *_mapquest_aerial_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom);
+static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
+static char *_nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat);
+/*
+static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
+static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat);
+*/
 
-struct _Route_Dump
+static Map_Sources_Tab default_map_sources_tab[] =
 {
-   int id;
-   char *fname;
-   double distance;
-   char *description;
-   char *coordinates;
+     {"Mapnik", 0, 18, _mapnik_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
+     {"Osmarender", 0, 17, _osmarender_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
+     {"CycleMap", 0, 16, _cyclemap_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
+     {"MapQuest", 0, 18, _mapquest_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
+     {"MapQuest Open Aerial", 0, 11, _mapquest_aerial_url_cb, ELM_MAP_ROUTE_SOURCE_YOURS, _yours_url_cb, _nominatim_url_cb, NULL, NULL},
 };
 
-enum _Route_Xml_Attribute
-{
-   ROUTE_XML_NONE,
-   ROUTE_XML_DISTANCE,
-   ROUTE_XML_DESCRIPTION,
-   ROUTE_XML_COORDINATES,
-   ROUTE_XML_LAST
-} Route_Xml_Attibute;
-
-struct _Name_Dump
-{
-   int id;
-   char *address;
-   double lon;
-   double lat;
-};
-
-enum _Name_Xml_Attribute
-{
-   NAME_XML_NONE,
-   NAME_XML_NAME,
-   NAME_XML_LON,
-   NAME_XML_LAT,
-   NAME_XML_LAST
-} Name_Xml_Attibute;
-
-enum _Zoom_Method
-{
-   ZOOM_METHOD_NONE,
-   ZOOM_METHOD_IN,
-   ZOOM_METHOD_OUT,
-   ZOOM_METHOD_LAST
-} Zoom_Mode;
-
-enum _Track_Xml_Attribute
-{
-   TRACK_XML_NONE,
-   TRACK_XML_COORDINATES,
-   TRACK_XML_LAST
-} Track_Xml_Attibute;
-
-static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_NULL;
-static const char *widtype = NULL;
-static int idnum = 1;
+static const char *widtype = NULL;
+static Evas_Smart_Class parent_sc = EVAS_SMART_CLASS_INIT_NULL;
+static Evas_Smart_Class sc;
+static Evas_Smart *smart;
+static int idnum = 1;
 
 static const char SIG_CHANGED[] = "changed";
 static const char SIG_CLICKED[] = "clicked";
@@ -503,46 +441,12 @@ static const Evas_Smart_Cb_Description _signals[] = {
        {NULL, NULL}
 };
 
-static void _pan_calculate(Evas_Object *obj);
-
-static void _rect_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
-static void _del_hook(Evas_Object *obj);
-static void _theme_hook(Evas_Object *obj);
-static void _on_focus_hook(void *data, Evas_Object *obj);
-static void _sizing_eval(Evas_Object *obj);
-static void _calc_job(void *data);
-static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
-                             Evas_Callback_Type type, void *event_info);
-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);
-static void grid_load(Evas_Object *obj, Grid *g);
-
-static void _process_download_list(Evas_Object *obj);
-static void _add_download_list(Evas_Object *obj, Grid_Item *gi);
-
-static void _group_object_create(Marker_Group *group);
-static void _group_object_free(Marker_Group *group);
-static void _group_open_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
-static void _group_bringin_cb(void *data, Evas_Object *obj, const char *emission, const char *soure);
-static void _group_bubble_create(Marker_Group *group);
-static void _group_bubble_free(Marker_Group *group);
-static void _group_bubble_place(Marker_Group *group);
-
-static int _group_bubble_content_update(Marker_Group *group);
-static void _group_bubble_content_free(Marker_Group *group);
-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);
-static void _bubble_sc_hints_changed_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
-
-static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
-static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
-
-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);
-static void track_place(Evas_Object *obj, Grid *g, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh);
-
 static Eina_Bool
 module_list_cb(Eina_Module *m, void *data)
 {
-   ELM_CHECK_WIDTYPE(data, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(data);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,EINA_FALSE);
+   Widget_Data *wd = data;
+
    Map_Sources_Tab *s;
    ElmMapModuleSourceFunc source;
    ElmMapModuleZoomMinFunc zoom_min;
@@ -555,12 +459,11 @@ module_list_cb(Eina_Module *m, void *data)
    ElmMapModuleCoordIntoGeoFunc coord_into_geo;
    const char *file;
 
-   if (!wd) return EINA_FALSE;
-
    file = eina_module_file_get(m);
    if (!eina_module_load(m))
      {
-        ERR("could not load module \"%s\": %s", file, eina_error_msg_get(eina_error_get()));
+        ERR("could not load module \"%s\": %s", file,
+            eina_error_msg_get(eina_error_get()));
         return EINA_FALSE;
      }
 
@@ -573,14 +476,15 @@ module_list_cb(Eina_Module *m, void *data)
    name_url = eina_module_symbol_get(m, "map_module_name_url_get");
    geo_into_coord = eina_module_symbol_get(m, "map_module_geo_into_coord");
    coord_into_geo = eina_module_symbol_get(m, "map_module_coord_into_geo");
-   if ((!source) || (!zoom_min) || (!zoom_max) || (!url) || (!route_source) || (!route_url) || (!name_url) || (!geo_into_coord) || (!coord_into_geo))
+   if ((!source) || (!zoom_min) || (!zoom_max) || (!url) || (!route_source) ||
+       (!route_url) || (!name_url) || (!geo_into_coord) || (!coord_into_geo))
      {
-        WRN("could not find map_module_source_get() in module \"%s\": %s", file, eina_error_msg_get(eina_error_get()));
+        WRN("could not find map_module_source_get() in module \"%s\": %s",
+            file, eina_error_msg_get(eina_error_get()));
         eina_module_unload(m);
         return EINA_FALSE;
      }
-   s = calloc(1, sizeof(Map_Sources_Tab));
-   EINA_SAFETY_ON_NULL_RETURN_VAL(s, EINA_FALSE);
+   s = ELM_NEW(Map_Sources_Tab);
    s->name = source();
    s->zoom_min = zoom_min();
    s->zoom_max = zoom_max();
@@ -590,35 +494,25 @@ module_list_cb(Eina_Module *m, void *data)
    s->name_url_cb = name_url;
    s->geo_into_coord = geo_into_coord;
    s->coord_into_geo = coord_into_geo;
-   wd->map_sources_tab = eina_list_append(wd->map_sources_tab, s);
+   wd->srcs = eina_list_append(wd->srcs, s);
 
+   eina_module_unload(m);
    return EINA_TRUE;
 }
 
 static void
-module_init(void *data)
+source_init(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
-
-   if (!wd) return;
-   wd->modules = eina_module_list_get(wd->modules, MODULES_PATH, 1, &module_list_cb, data);
-}
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-static void
-source_init(void *data)
-{
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
    Map_Sources_Tab *s;
-   Eina_List *l;
    unsigned int idx;
+   Eina_Array *modules = NULL;
+   Eina_List *l;
 
-   if (!wd) return;
-   for (idx = 0; idx < sizeof(default_map_sources_tab)/sizeof(Map_Sources_Tab); idx++)
+   for (idx = 0; idx < (sizeof(default_map_sources_tab) / sizeof(Map_Sources_Tab)); idx++)
      {
-        s = calloc(1, sizeof(Map_Sources_Tab));
-        EINA_SAFETY_ON_NULL_RETURN(s);
+        s = ELM_NEW(Map_Sources_Tab);
         s->name = default_map_sources_tab[idx].name;
         s->zoom_min = default_map_sources_tab[idx].zoom_min;
         s->zoom_max = default_map_sources_tab[idx].zoom_max;
@@ -628,1310 +522,1317 @@ source_init(void *data)
         s->name_url_cb = default_map_sources_tab[idx].name_url_cb;
         s->geo_into_coord = default_map_sources_tab[idx].geo_into_coord;
         s->coord_into_geo = default_map_sources_tab[idx].coord_into_geo;
-        wd->map_sources_tab = eina_list_append(wd->map_sources_tab, s);
-        if (!idx) wd->src = s;
+        wd->srcs = eina_list_append(wd->srcs, s);
+        if (!idx)
+          {
+             wd->src = s;
+             wd->zoom_min = s->zoom_min;
+             wd->zoom_max = s->zoom_max;
+          }
      }
-   module_init(data);
+   modules = eina_module_list_get(modules, MODULES_PATH, 1, &module_list_cb, wd);
+   eina_array_free(modules);
 
-   int n = eina_list_count(wd->map_sources_tab);
-   wd->source_names = malloc(sizeof(char *) * (n + 1));
-   if (!wd->source_names)
-     {
-        ERR("init source names failed.");
-        return;
-     }
+   wd->src_names = calloc((eina_list_count(wd->srcs) + 1), sizeof(char *));
    idx = 0;
-   EINA_LIST_FOREACH(wd->map_sources_tab, l, s)
+   EINA_LIST_FOREACH(wd->srcs, l, s)
      {
-        wd->source_names[idx] = strdup(s->name);
-        INF("source : %s", wd->source_names[idx]);
-        if (s->zoom_min < wd->zoom_min) wd->zoom_min = s->zoom_min;
-        if (s->zoom_max > wd->zoom_max) wd->zoom_max = s->zoom_max;
+        eina_stringshare_replace(&wd->src_names[idx], s->name);
+        INF("source : %s", wd->src_names[idx]);
         idx++;
      }
-   wd->source_names[idx] = NULL;
 }
 
 static void
-obj_rotate_zoom(void *data, Evas_Object *obj)
+_edj_marker_size_get(Widget_Data *wd, Evas_Coord *w, Evas_Coord *h)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
-   int ow, oh, iw, ih;
-   if ((!wd->pinch.cx) && (!wd->pinch.cy))
-     {
-        wd->pinch.cx = wd->rotate.cx;
-        wd->pinch.cy = wd->rotate.cy;
-     }
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN(w);
+   EINA_SAFETY_ON_NULL_RETURN(h);
 
-   evas_map_util_points_populate_from_object_full(wd->map, obj, 0);
-   evas_object_image_size_get(obj, &iw, &ih);
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   if ((ow < iw) || (oh < ih))
-     {
-        ow *= (double)iw / ow;
-        oh *= (double)ih / oh;
-        evas_map_point_image_uv_set(wd->map, 1, ow, 0);
-        evas_map_point_image_uv_set(wd->map, 2, ow, oh);
-        evas_map_point_image_uv_set(wd->map, 3, 0, oh);
-     }
-   evas_map_util_zoom(wd->map, wd->pinch.level, wd->pinch.level, wd->pinch.cx, wd->pinch.cy);
-   evas_map_util_rotate(wd->map, wd->rotate.d, wd->rotate.cx, wd->rotate.cy);
-   evas_object_map_enable_set(obj, EINA_TRUE);
-   evas_object_map_set(obj, wd->map);
+   Evas_Object *edj;
+   const char *s;
+
+   edj = edje_object_add(evas_object_evas_get(wd->obj));
+   _elm_theme_object_set(wd->obj, edj, "map/marker", "radio",
+                         elm_widget_style_get(wd->obj));
+   s = edje_object_data_get(edj, "size_w");
+   if (s) *w = atoi(s);
+   else   *w = 0;
+   s = edje_object_data_get(edj, "size_h");
+   if (s) *h = atoi(s);
+   else   *h = 0;
+   evas_object_del(edj);
 }
 
 static void
-#ifdef ELM_EMAP
-track_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)
-#else
-track_place(Evas_Object *obj __UNUSED__, Grid *g __UNUSED__, Evas_Coord px __UNUSED__, Evas_Coord py __UNUSED__, Evas_Coord ox __UNUSED__, Evas_Coord oy __UNUSED__, Evas_Coord ow __UNUSED__, Evas_Coord oh __UNUSED__)
-#endif
+_coord_rotate(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)
 {
-#ifdef ELM_EMAP
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Eina_List *l;
-   Evas_Object *route;
-   int xmin, xmax, ymin, ymax;
-
-   if (!wd) return;
-   Evas_Coord size = pow(2.0, wd->zoom)*wd->tsize;
+   EINA_SAFETY_ON_NULL_RETURN(xx);
+   EINA_SAFETY_ON_NULL_RETURN(yy);
 
-   EINA_LIST_FOREACH(wd->track, l, route)
-     {
-        elm_map_utils_convert_geo_into_coord(wd->obj, elm_route_lon_min_get(route), elm_route_lat_max_get(route), size, &xmin, &ymin);
-        elm_map_utils_convert_geo_into_coord(wd->obj, elm_route_lon_max_get(route), elm_route_lat_min_get(route), size, &xmax, &ymax);
+   double r = (degree * M_PI) / 180.0;
+   double tx, ty, ttx, tty;
 
-        if( !(xmin < px && xmax < px) && !(xmin > px+ow && xmax > px+ow))
-        {
-           if( !(ymin < py && ymax < py) && !(ymin > py+oh && ymax > py+oh))
-           {
-              //display the route
-              evas_object_move(route, xmin - px + ox, ymin - py + oy);
-              evas_object_resize(route, xmax - xmin, ymax - ymin);
+   tx = x - cx;
+   ty = y - cy;
 
-              evas_object_raise(route);
-              obj_rotate_zoom(obj, route);
-              evas_object_show(route);
+   ttx = tx * cos(r);
+   tty = tx * sin(r);
+   tx = ttx + (ty * cos(r + M_PI_2));
+   ty = tty + (ty * sin(r + M_PI_2));
 
-              continue;
-           }
-        }
-        //the route is not display
-        evas_object_hide(route);
-     }
-#endif
+   *xx = tx + cx;
+   *yy = ty + cy;
 }
+
 static void
-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)
+_viewport_size_get(Widget_Data *wd, Evas_Coord *vw, Evas_Coord *vh)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Eina_List *lr, *lp, *ln;
-   Path_Node *n;
-   Evas_Object *p;
-   Elm_Map_Route *r;
-   int nodes;
-   int x, y, rx, ry;
-   double a;
-
-   if (!wd) return;
-   Evas_Coord size = pow(2.0, wd->zoom)*wd->tsize;
-
-   EINA_LIST_FOREACH(wd->route, lr, r)
-     {
-        EINA_LIST_FOREACH(r->path, lp, p)
-          {
-             evas_object_polygon_points_clear(p);
-          }
-
-        evas_object_geometry_get(wd->rect, &rx, &ry, NULL, NULL);
-        nodes = eina_list_count(r->nodes);
-
-        EINA_LIST_FOREACH(r->nodes, ln, n)
-          {
-             if ((!wd->zoom) || ((n->idx) &&
-                 ((n->idx % (int)ceil((double)nodes/(double)size*100.0))))) continue;
-             if (r->inbound)
-               {
-                  elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
-                  if ((x >= px - ow) && (x <= (px + ow*2)) &&
-                      (y >= py - oh) && (y <= (py + oh*2)))
-                    {
-                       x = x - px + rx;
-                       y = y - py + ry;
-
-                       p = eina_list_nth(r->path, n->idx);
-                       a = (double)(y - r->y) / (double)(x - r->x);
-                       if ((abs(a) >= 1) || (r->x == x))
-                         {
-                            evas_object_polygon_point_add(p, r->x - 3, r->y);
-                            evas_object_polygon_point_add(p, r->x + 3, r->y);
-                            evas_object_polygon_point_add(p, x + 3, y);
-                            evas_object_polygon_point_add(p, x - 3, y);
-                         }
-                       else
-                         {
-                            evas_object_polygon_point_add(p, r->x, r->y - 3);
-                            evas_object_polygon_point_add(p, r->x, r->y + 3);
-                            evas_object_polygon_point_add(p, x, y + 3);
-                            evas_object_polygon_point_add(p, x, y - 3);
-                         }
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-                       evas_object_color_set(p, r->color.r, r->color.g, r->color.b, r->color.a);
-                       evas_object_raise(p);
-                       obj_rotate_zoom(obj, p);
-                       evas_object_show(p);
-                       r->x = x;
-                       r->y = y;
-                    }
-                  else r->inbound = EINA_FALSE;
-               }
-             else
-               {
-                  elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
-                  if ((x >= px - ow) && (x <= (px + ow*2)) &&
-                      (y >= py - oh) && (y <= (py + oh*2)))
-                    {
-                       r->x = x - px + rx;
-                       r->y = y - py + ry;
-                       r->inbound = EINA_TRUE;
-                    }
-                  else r->inbound = EINA_FALSE;
-               }
-          }
-          r->inbound = EINA_FALSE;
-     }
+   Evas_Coord x, y, w, h;
+   evas_object_geometry_get(wd->pan_smart, &x, &y, &w, &h);
+   if (vw) *vw = (x * 2) + w;
+   if (vh) *vh = (y * 2) + h;
 }
 
 static void
-rect_place(Evas_Object *obj, Evas_Coord px, Evas_Coord py, Evas_Coord ox, Evas_Coord oy, Evas_Coord ow, Evas_Coord oh)
+_pan_geometry_get(Widget_Data *wd, Evas_Coord *px, Evas_Coord *py)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord ax, ay, gw, gh, hh, ww;
-
-   if (!wd) return;
-   evas_object_geometry_get(wd->rect, NULL, NULL, &ww, &hh);
-
-   ax = 0;
-   ay = 0;
-   gw = wd->size.w;
-   gh = wd->size.h;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if ((ww == gw) && (hh == gh)) return;
+   Evas_Coord x, y, vx, vy, vw, vh;
+   elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
+   evas_object_geometry_get(wd->pan_smart, &vx, &vy, &vw, &vh);
+   x = -x;
+   y = -y;
+   if (vw > wd->size.w) x += (((vw - wd->size.w) / 2) + vx);
+   else x -= vx;
+   if (vh > wd->size.h) y += (((vh - wd->size.h) / 2) + vy);
+   else y -= vy;
+   if (px) *px = x;
+   if (py) *py = y;
+ }
 
-   if (ow > gw) ax = (ow - gw) / 2;
-   if (oh > gh) ay = (oh - gh) / 2;
-   evas_object_move(wd->rect,
-                    ox + 0 - px + ax,
-                    oy + 0 - py + ay);
-   evas_object_resize(wd->rect, gw, gh);
+static void
+_obj_rotate(Widget_Data *wd, Evas_Object *obj)
+{
+   Evas_Coord w, h, ow, oh;
+   evas_map_util_points_populate_from_object(wd->map, obj);
 
-   if (wd->show.show)
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   evas_object_image_size_get(obj, &w, &h);
+   if ((w > ow) || (h > oh))
      {
-        wd->show.show = EINA_FALSE;
-        elm_smart_scroller_child_region_show(wd->scr, wd->show.x, wd->show.y, wd->show.w, wd->show.h);
+        evas_map_point_image_uv_set(wd->map, 0, 0, 0);
+        evas_map_point_image_uv_set(wd->map, 1, w, 0);
+        evas_map_point_image_uv_set(wd->map, 2, w, h);
+        evas_map_point_image_uv_set(wd->map, 3, 0, h);
      }
+   evas_map_util_rotate(wd->map, wd->rotate.d, wd->rotate.cx, wd->rotate.cy);
+
+   evas_object_map_set(obj, wd->map);
+   evas_object_map_enable_set(obj, EINA_TRUE);
 }
 
 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)
+_obj_place(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord ax, ay, gw, gh, tx, ty;
-   Eina_List *l, *markers;
-   Eina_Matrixsparse_Cell *cell;
-   Marker_Group *group;
-   int xx, yy, ww, hh;
-   char buf[PATH_MAX];
-   int y, x;
-   int g_xx, g_yy, g_hh, g_ww;
+   EINA_SAFETY_ON_NULL_RETURN(obj);
 
-   if (!wd) return;
+   evas_object_move(obj, x, y);
+   evas_object_resize(obj, w, h);
+   evas_object_show(obj);
+}
 
-   ax = 0;
-   ay = 0;
-   gw = wd->size.w;
-   gh = wd->size.h;
-   if (ow > gw) ax = (ow - gw) / 2;
-   if (oh > gh) ay = (oh - gh) / 2;
+static void
+_bubble_update(Marker_Bubble *bubble, Eina_List *contents)
+{
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   EINA_SAFETY_ON_NULL_RETURN(contents);
 
-   if (wd->zoom != wd->marker_zoom)
-     {
-        EINA_LIST_FREE(wd->cells_displayed, cell)
-          {
-             EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
-               {
-                  if (group->obj) _group_object_free(group);
-               }
-          }
-     }
-   wd->marker_zoom = wd->zoom;
-
-   if ((wd->paused_markers)
-       && ((wd->size.nw != wd->size.w) || (wd->size.nh != wd->size.h)) )
-     return;
-
-   g_xx = wd->pan_x / wd->tsize;
-   if (g_xx < 0) g_xx = 0;
-   g_yy = wd->pan_y / wd->tsize;
-   if (g_yy < 0) g_yy = 0;
-   g_ww = (ow / wd->tsize) + 1;
-   if (g_xx + g_ww >= g->gw) g_ww = g->gw - g_xx - 1;
-   g_hh = (oh / wd->tsize) + 1;
-   if (g_yy + g_hh >= g->gh) g_hh = g->gh - g_yy - 1;
-
-   //hide groups no more displayed
-   EINA_LIST_FREE(wd->cells_displayed, cell)
-     {
-        eina_matrixsparse_cell_position_get(cell, (unsigned long *)&y, (unsigned long *)&x);
-        if ((y < g_yy) || (y > g_yy + g_hh) || (x < g_xx) || (x > g_xx + g_ww))
-          {
-             EINA_LIST_FOREACH(eina_matrixsparse_cell_data_get(cell), l, group)
-               {
-                  if (group->obj) _group_object_free(group);
-               }
-          }
-     }
+   Eina_List *l;
+   Evas_Object *c;
 
-   if (!wd->marker_zoom)
-     {
-        g_ww = 0;
-        g_hh = 0;
-     }
+   elm_box_clear(bubble->bx);
+   EINA_LIST_FOREACH(contents, l, c) elm_box_pack_end(bubble->bx, c);
+}
 
-   for (y = g_yy; y <= g_yy + g_hh; y++)
-     {
-        for (x = g_xx; x <= g_xx + g_ww; x++)
-          {
-             if (!wd->markers[wd->zoom]) continue;
-             eina_matrixsparse_cell_idx_get(wd->markers[wd->zoom], y, x, &cell);
-             if (!cell) continue;
-             wd->cells_displayed = eina_list_append(wd->cells_displayed, cell);
-             markers = eina_matrixsparse_cell_data_get(cell);
-             EINA_LIST_FOREACH(markers, l, group)
-               {
-                  if (!group->markers) continue;
-                  if (group->clas->zoom_displayed > wd->zoom) continue;
+static void
+_bubble_place(Marker_Bubble *bubble)
+{
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
 
-                  xx = group->x;
-                  yy = group->y;
-                  ww = group->w;
-                  hh = group->h;
+   Evas_Coord x, y, w, h;
+   Evas_Coord xx, yy, ww, hh;
+   const char *s;
 
-                  if (eina_list_count(group->markers) == 1)
-                    {
-                       Elm_Map_Marker *m = eina_list_data_get(group->markers);
-                       ww = m->clas->priv.edje_w;
-                       hh = m->clas->priv.edje_h;
-                    }
+   if ((!bubble->obj) || (!bubble->pobj)) return;
+   evas_object_geometry_get(bubble->pobj, &x, &y, &w, NULL);
 
-                  if (ww <= 0) ww = 1;
-                  if (hh <= 0) hh = 1;
+   s = edje_object_data_get(bubble->obj, "size_w");
+   if (s) ww = atoi(s);
+   else ww = 0;
 
-                  if ((gw != g->w) && (g->w > 0))
-                    {
-                       tx = xx;
-                       xx = ((long long )gw * xx) / g->w;
-                       ww = (((long long)gw * (tx + ww)) / g->w) - xx;
-                    }
-                  if ((gh != g->h) && (g->h > 0))
-                    {
-                       ty = yy;
-                       yy = ((long long)gh * yy) / g->h;
-                       hh = (((long long)gh * (ty + hh)) / g->h) - yy;
-                    }
+   edje_object_size_min_calc(bubble->obj, NULL, &hh);
+   s = edje_object_data_get(bubble->obj, "size_h");
+   if (s) h = atoi(s);
+   else h = 0;
+   if (hh < h) hh = h;
 
-                  if ((!group->clas->hide)
-                      && (xx-px+ax+ox >= ox) && (xx-px+ax+ox<= ox+ow)
-                      && (yy-py+ay+oy >= oy) && (yy-py+ay+oy<= oy+oh))
-                    {
-                       if (!group->obj) _group_object_create(group);
+   xx = x + (w / 2) - (ww / 2);
+   yy = y - hh;
 
-                       if (group->update_nbelems)
-                         {
-                            group->update_nbelems = EINA_FALSE;
-                            if (eina_list_count(group->markers) > 1)
-                              {
-                                 snprintf(buf, sizeof(buf), "%d", eina_list_count(group->markers));
-                                 edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", buf);
-                              }
-                            else
-                              edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", "");
-                         }
-                       evas_object_move(group->obj,
-                                        xx - px + ax + ox - ww/2,
-                                        yy - py + ay + oy - hh/2);
-                       if ((!wd->paused_markers) || (group->update_resize))
-                         {
-                            group->update_resize = EINA_FALSE;
-                            evas_object_resize(group->obj, ww, hh);
-                            obj_rotate_zoom(obj, group->obj);
-                         }
-                       if (group->update_raise)
-                         {
-                            group->update_raise = EINA_FALSE;
-                            evas_object_raise(group->obj);
-                            obj_rotate_zoom(obj, group->obj);
-                            evas_object_show(group->obj);
-                         }
-                       if (group->bubble) _group_bubble_place(group);
-                    }
-                  else if (group->obj)
-                    {
-                       _group_object_free(group);
-                    }
-               }
-          }
-     }
+   _obj_place(bubble->obj, xx, yy, ww, hh);
+   evas_object_raise(bubble->obj);
 }
 
 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)
+_bubble_sc_hints_changed_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord ax, ay, gw, gh, tx, ty;
-   int xx, yy, ww, hh;
+   Marker_Bubble *bubble = data;
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   _bubble_place(data);
+}
 
-   if (!wd) return;
-   ax = 0;
-   ay = 0;
-   gw = wd->size.w;
-   gh = wd->size.h;
-   if (ow > gw) ax = (ow - gw) / 2;
-   if (oh > gh) ay = (oh - gh) / 2;
+static void
+_bubble_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Marker_Bubble *bubble = data;
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   _bubble_place(bubble);
+}
 
-   Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
-   Eina_Matrixsparse_Cell *cell;
+static void
+_bubble_hide_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Marker_Bubble *bubble = data;
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   evas_object_hide(bubble->obj);
+}
 
-   EINA_ITERATOR_FOREACH(it, cell)
-     {
-        Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
+static void
+_bubble_show_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Marker_Bubble *bubble = data;
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   _bubble_place(bubble);
+}
 
-        xx = gi->out.x;
-        yy = gi->out.y;
-        ww = gi->out.w;
-        hh = gi->out.h;
-        if ((gw != g->w) && (g->w > 0))
-          {
-             tx = xx;
-             xx = ((long long )gw * xx) / g->w;
-             ww = (((long long)gw * (tx + ww)) / g->w) - xx;
-          }
-        if ((gh != g->h) && (g->h > 0))
-          {
-             ty = yy;
-             yy = ((long long)gh * yy) / g->h;
-             hh = (((long long)gh * (ty + hh)) / g->h) - yy;
-          }
-        evas_object_move(gi->img,
-                         xx - px + ax + ox,
-                         yy - py + ay + oy);
+static void
+_bubble_move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Marker_Bubble *bubble = data;
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
+   _bubble_place(bubble);
+}
 
-        evas_object_resize(gi->img, ww, hh);
+static void
+_bubble_free(Marker_Bubble* bubble)
+{
+   EINA_SAFETY_ON_NULL_RETURN(bubble);
 
-        obj_rotate_zoom(obj, gi->img);
-        /*evas_object_move(gi->txt,
-                           xx - px + ax + ox,
-                           yy - py + ay + oy);
+   evas_object_del(bubble->bx);
+   evas_object_del(bubble->sc);
+   evas_object_del(bubble->obj);
+   free(bubble);
+}
 
-          evas_object_resize(gi->txt, ww, hh);
-         */
-     }
-   eina_iterator_free(it);
+static Marker_Bubble*
+_bubble_create(Evas_Object *pobj, Widget_Data *wd)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pobj, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+
+   Marker_Bubble *bubble = ELM_NEW(Marker_Bubble);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bubble, NULL);
+
+   bubble->wd = wd;
+   bubble->pobj = pobj;
+   evas_object_event_callback_add(pobj, EVAS_CALLBACK_HIDE, _bubble_hide_cb,
+                                  bubble);
+   evas_object_event_callback_add(pobj, EVAS_CALLBACK_SHOW, _bubble_show_cb,
+                                  bubble);
+   evas_object_event_callback_add(pobj, EVAS_CALLBACK_MOVE, _bubble_move_cb,
+                                  bubble);
+
+   bubble->obj = edje_object_add(evas_object_evas_get(pobj));
+   _elm_theme_object_set(wd->obj, bubble->obj , "map", "marker_bubble",
+                         elm_widget_style_get(wd->obj));
+   evas_object_event_callback_add(bubble->obj, EVAS_CALLBACK_MOUSE_UP,
+                                  _bubble_mouse_up_cb, bubble);
+
+   bubble->sc = elm_scroller_add(bubble->obj);
+   elm_widget_style_set(bubble->sc, "map_bubble");
+   elm_scroller_content_min_limit(bubble->sc, EINA_FALSE, EINA_TRUE);
+   elm_scroller_policy_set(bubble->sc, ELM_SCROLLER_POLICY_AUTO,
+                           ELM_SCROLLER_POLICY_OFF);
+   elm_scroller_bounce_set(bubble->sc, _elm_config->thumbscroll_bounce_enable,
+                           EINA_FALSE);
+   edje_object_part_swallow(bubble->obj, "elm.swallow.content", bubble->sc);
+   evas_object_event_callback_add(bubble->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                  _bubble_sc_hints_changed_cb, bubble);
+
+   bubble->bx = elm_box_add(bubble->sc);
+   evas_object_size_hint_align_set(bubble->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(bubble->bx, EVAS_HINT_EXPAND,
+                                    EVAS_HINT_EXPAND);
+   elm_box_horizontal_set(bubble->bx, EINA_TRUE);
+   elm_object_content_set(bubble->sc, bubble->bx);
+
+   return bubble;
 }
 
 static void
-_tile_update(Grid_Item *gi)
+_marker_group_update(Marker_Group* group, Elm_Map_Group_Class *clas, Eina_List *markers)
 {
-   evas_object_image_file_set(gi->img, gi->file, NULL);
-   Evas_Load_Error err = evas_object_image_load_error_get(gi->img);
-   if (err != EVAS_LOAD_ERROR_NONE)
-     {
-        ERR("Image loading error (%s): %s", gi->file, evas_load_error_str(err));
-        ecore_file_remove(gi->file);
-        gi->file_have = EINA_FALSE;
-     }
-   else
+   EINA_SAFETY_ON_NULL_RETURN(group);
+   EINA_SAFETY_ON_NULL_RETURN(clas);
+   EINA_SAFETY_ON_NULL_RETURN(markers);
+   Widget_Data *wd = clas->wd;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+
+   char buf[PATH_MAX];
+   Eina_List *l;
+   Elm_Map_Marker *marker;
+   int cnt = 0;
+   int sum_x = 0, sum_y = 0;
+
+   EINA_LIST_FOREACH(markers, l, marker)
      {
-        obj_rotate_zoom(gi->wd->obj, gi->img);
-        evas_object_show(gi->img);
-        gi->file_have = EINA_TRUE;
-        //evas_object_text_text_set(gi->txt, gi->file);
-        //evas_object_show(gi->txt);
+        sum_x += marker->x;
+        sum_y += marker->y;
+        cnt++;
      }
-}
 
-static void
-_tile_downloaded(void *data, const char *file __UNUSED__, int status)
-{
-   Grid_Item *gi = data;
+   group->x = sum_x / cnt;
+   group->y = sum_y / cnt;
+   _edj_marker_size_get(wd, &group->w, &group->h);
+   group->w *=2;
+   group->h *=2;
+   group->clas = clas;
+   group->markers = markers;
 
-   gi->job = NULL;
+   if (clas->style) elm_layout_theme_set(group->obj, "map/marker", clas->style,
+                                         elm_widget_style_get(wd->obj));
+   else elm_layout_theme_set(group->obj, "map/marker", "radio",
+                             elm_widget_style_get(wd->obj));
 
-   if (status == 200)
-     {
-        DBG("Download success from %s to %s", gi->source, gi->file);
-        _tile_update(gi);
-        gi->wd->finish_num++;
-     }
-   else
-     {
-        WRN("Download failed from %s to %s (%d) ", gi->source, gi->file, status);
-        ecore_file_remove(gi->file);
-        gi->file_have = EINA_FALSE;
-     }
 
-   gi->wd->download_num--;
-   evas_object_smart_callback_call(gi->wd->obj, SIG_DOWNLOADED, NULL);
-   if (!gi->wd->download_num)
+   if (clas->func.icon_get)
      {
-        edje_object_signal_emit(elm_smart_scroller_edje_object_get(gi->wd->scr), "elm,state,busy,stop", "elm");
-        evas_object_smart_callback_call(gi->wd->obj, SIG_LOADED_DETAIL, NULL);
+        Evas_Object *icon = NULL;
+
+        icon = elm_object_part_content_get(group->obj, "elm.icon");
+        if (icon) evas_object_del(icon);
+
+        icon = clas->func.icon_get(wd->obj, clas->data);
+        elm_object_part_content_set(group->obj, "elm.icon", icon);
      }
-   _process_download_list(gi->wd->obj);
+   snprintf(buf, sizeof(buf), "%d", cnt);
+   edje_object_part_text_set(elm_layout_edje_get(group->obj), "elm.text", buf);
+
+   if (group->bubble)
+      {
+         Eina_List *l;
+         Elm_Map_Marker *marker;
+         Eina_List *contents = NULL;
+
+         EINA_LIST_FOREACH(group->markers, l, marker)
+           {
+              Evas_Object *c = marker->clas->func.get(marker->wd->obj,
+                                                      marker, marker->data);
+              if (c) contents = eina_list_append(contents, c);
+           }
+         _bubble_update(group->bubble, contents);
+      }
 }
 
 static void
-_process_download_list(Evas_Object *obj)
+_marker_group_bubble_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Eina_List *l, *ll;
-   Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, tx, ty, gw, gh, xx, yy, ww, hh;
-   Grid_Item *gi;
-
-   evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
-   evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Marker_Group *group = data;
+   Eina_List *l;
+   Elm_Map_Marker *marker;
+   Eina_List *contents = NULL;
 
-   gw = wd->size.w;
-   gh = wd->size.h;
+   if (!group->bubble) group->bubble = _bubble_create(group->obj, group->wd);
 
-   EINA_LIST_REVERSE_FOREACH_SAFE(wd->download_list, l, ll, gi)
+   EINA_LIST_FOREACH(group->markers, l, marker)
      {
-        xx = gi->out.x;
-        yy = gi->out.y;
-        ww = gi->out.w;
-        hh = gi->out.h;
-
-        if ((gw != gi->g->w) && (gi->g->w > 0))
-          {
-             tx = xx;
-             xx = ((long long )gw * xx) / gi->g->w;
-             ww = (((long long)gw * (tx + ww)) / gi->g->w) - xx;
-          }
-        if ((gh != gi->g->h) && (gi->g->h > 0))
-          {
-             ty = yy;
-             yy = ((long long)gh * yy) / gi->g->h;
-             hh = (((long long)gh * (ty + hh)) / gi->g->h) - yy;
-          }
-        if (!ELM_RECTS_INTERSECT(xx - wd->pan_x + ox,
-                                 yy  - wd->pan_y + oy,
-                                 ww, hh,
-                                 cvx, cvy, cvw, cvh) ||
-           (gi->zoom != wd->zoom))
-          {
-             wd->download_list = eina_list_remove(wd->download_list, gi);
-             continue;
-          }
-
-        if (gi->wd->download_num >= MAX_CONCURRENT_DOWNLOAD) break;
-
-        Eina_Bool ret = ecore_file_download_full(gi->source, gi->file, _tile_downloaded, NULL, gi, &(gi->job), wd->ua);
-        if (!ret || !gi->job) ERR("Can't start to download from %s to %s", gi->source, gi->file);
-        else
-          {
-             gi->wd->download_num++;
-             wd->try_num++;
-             wd->download_list = eina_list_remove(wd->download_list, gi);
-             if (wd->download_num == 1)
-               edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,state,busy,start", "elm");
-          }
+        if (group->wd->markers_max_num <= eina_list_count(contents)) break;
+        Evas_Object *c = marker->clas->func.get(marker->wd->obj,
+                                                marker, marker->data);
+        if (c) contents = eina_list_append(contents, c);
      }
+   _bubble_update(group->bubble, contents);
+   _bubble_place(group->bubble);
 }
 
 static void
-_add_download_list(Evas_Object *obj, Grid_Item *gi)
+_marker_group_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(data);
 
-   wd->download_list = eina_list_remove(wd->download_list, gi);
-   wd->download_list = eina_list_append(wd->download_list, gi);
-   _process_download_list(obj);
+   double lon, lat;
+   Marker_Group *group = data;
+   elm_map_utils_convert_coord_into_geo(group->wd->obj, group->x, group->y,
+                                        group->wd->size.w, &lon, &lat);
+   elm_map_geo_region_bring_in(group->wd->obj, lon, lat);
 }
 
 static void
-grid_create_all(Evas_Object *obj)
+_marker_group_free(Marker_Group* group)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Grid *g;
-   int zoom = 0;
+   EINA_SAFETY_ON_NULL_RETURN(group);
 
-   EINA_SAFETY_ON_NULL_RETURN(wd);
-   EINA_SAFETY_ON_NULL_RETURN(wd->src);
+   if (group->bubble) _bubble_free(group->bubble);
 
-   for (zoom = wd->src->zoom_min; zoom <= wd->src->zoom_max; zoom++)
-     {
-        g = calloc(1, sizeof(Grid));
-        EINA_SAFETY_ON_NULL_RETURN(g);
-        g->zoom = zoom;
-        g->tsize = wd->tsize;
-        g->wd = wd;
-        int size =  pow(2.0, g->zoom);
-        g->gw = size;
-        g->gh = size;
-        g->w = g->tsize * g->gw;
-        g->h = g->tsize * g->gh;
+   eina_list_free(group->markers);
+   evas_object_del(group->obj);
 
-        g->grid = eina_matrixsparse_new(g->gh, g->gw, NULL, NULL);
-        wd->grids = eina_list_append(wd->grids, g);
-     }
+   free(group);
 }
 
-static void
-grid_clear_all(Evas_Object *obj)
+static Marker_Group*
+_marker_group_create(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Grid *g;
-   Grid_Item *gi;
-
-   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
 
-   EINA_LIST_FREE(wd->grids, g)
-     {
-        Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
-        Eina_Matrixsparse_Cell *cell;
+   Marker_Group *group = ELM_NEW(Marker_Group);
 
-        EINA_ITERATOR_FOREACH(it, cell)
-          {
-             gi = eina_matrixsparse_cell_data_get(cell);
-             evas_object_del(gi->img);
-             //evas_object_del(gi->txt);
+   group->wd = wd;
+   group->obj = elm_layout_add(wd->obj);
+   evas_object_smart_member_add(group->obj, wd->pan_smart);
+   evas_object_stack_above(group->obj, wd->sep_maps_markers);
+   elm_layout_theme_set(group->obj, "map/marker", "radio",
+                        elm_widget_style_get(wd->obj));
+   edje_object_signal_callback_add(elm_layout_edje_get(group->obj),
+                                   "open", "elm", _marker_group_bubble_open_cb,
+                                   group);
+   edje_object_signal_callback_add(elm_layout_edje_get(group->obj),
+                                   "bringin", "elm", _marker_group_bringin_cb,
+                                   group);
+   return group;
+}
 
-             if (gi->job)
-               {
-                  DBG("DOWNLOAD abort %s", gi->file);
-                  ecore_file_download_abort(gi->job);
-                  ecore_file_remove(gi->file);
-                  gi->file_have = EINA_FALSE;
-                  gi->job = NULL;
-                  wd->try_num--;
-               }
-             if (gi->file)   eina_stringshare_del(gi->file);
-             if (gi->source) eina_stringshare_del(gi->source);
-             free(gi);
-          }
-        eina_matrixsparse_free(g->grid);
-        eina_iterator_free(it);
-        free(g);
-     }
+static void
+_marker_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
+{
+   Elm_Map_Marker *marker = data;
+   EINA_SAFETY_ON_NULL_RETURN(marker);
+   elm_map_geo_region_bring_in(marker->wd->obj, marker->longitude, marker->latitude);
+}
 
-   EINA_LIST_FREE(wd->download_list, gi);
-   if (!ecore_file_recursive_rm("/tmp/elm_map/")) WRN("Deletion of /tmp/elm_map/ failed");
+static void
+_marker_bubble_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Elm_Map_Marker *marker = data;
 
+   if (!marker->bubble) marker->bubble = _bubble_create(marker->obj, marker->wd);
+   evas_object_smart_changed(marker->wd->pan_smart);
 }
 
 static void
-grid_unload(Evas_Object *obj, Grid *g)
+_marker_update(Elm_Map_Marker *marker)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   Eina_Iterator *it;
-   Eina_Matrixsparse_Cell *cell;
-   Grid_Item *gi;
+   EINA_SAFETY_ON_NULL_RETURN(marker);
+   Elm_Map_Marker_Class *clas = marker->clas;
+   EINA_SAFETY_ON_NULL_RETURN(clas);
 
-   EINA_SAFETY_ON_NULL_RETURN(wd);
+   if (clas->style) elm_layout_theme_set(marker->obj, "map/marker", clas->style,
+                                         elm_widget_style_get(marker->wd->obj));
+   else elm_layout_theme_set(marker->obj, "map/marker", "radio",
+                             elm_widget_style_get(marker->wd->obj));
 
-   it = eina_matrixsparse_iterator_new(g->grid);
-   EINA_ITERATOR_FOREACH(it, cell)
+   if (clas->func.icon_get)
      {
-        gi = eina_matrixsparse_cell_data_get(cell);
+        Evas_Object *icon = NULL;
 
-        if (gi->file_have)
-          {
-             evas_object_hide(gi->img);
-             //evas_object_hide(gi->txt);
-             evas_object_image_file_set(gi->img, NULL, NULL);
-          }
-        else if (gi->job)
+        icon = elm_object_part_content_get(marker->obj, "elm.icon");
+        if (icon) evas_object_del(icon);
+
+        icon = clas->func.icon_get(marker->wd->obj, marker, marker->data);
+        elm_object_part_content_set(marker->obj, "elm.icon", icon);
+     }
+
+   elm_map_utils_convert_geo_into_coord(marker->wd->obj, marker->longitude,
+                                        marker->latitude, marker->wd->size.w,
+                                        &(marker->x), &(marker->y));
+
+    if (marker->bubble)
+      {
+         if (marker->content) evas_object_del(marker->content);
+         if (marker->clas->func.get)
+            marker->content = marker->clas->func.get(marker->wd->obj, marker,
+                                                     marker->data);
+        if (marker->content)
           {
-             DBG("DOWNLOAD abort %s", gi->file);
-             ecore_file_download_abort(gi->job);
-             ecore_file_remove(gi->file);
-             gi->job = NULL;
-             wd->try_num--;
+             Eina_List *contents = NULL;
+             contents = eina_list_append(contents, marker->content);
+             _bubble_update(marker->bubble, contents);
           }
-     }
-   eina_iterator_free(it);
+      }
 }
 
 
+
 static void
-grid_load(Evas_Object *obj, Grid *g)
+_marker_place(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   int x, y;
-   int size;
-   Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh, tx, ty, gw, gh, xx, yy, ww, hh;
-   Eina_Iterator *it;
-   Eina_Matrixsparse_Cell *cell;
-   Grid_Item *gi;
-
    EINA_SAFETY_ON_NULL_RETURN(wd);
-   EINA_SAFETY_ON_NULL_RETURN(wd->src);
 
-   evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
-   evas_output_viewport_get(evas_object_evas_get(wd->obj), &cvx, &cvy, &cvw, &cvh);
+   Eina_List *l;
 
-   gw = wd->size.w;
-   gh = wd->size.h;
+   Elm_Map_Marker *marker;
+   Elm_Map_Group_Class *group_clas;
 
-   if ((gw <= 0) || (gh <= 0)) return;
+   Evas_Coord gw, gh;
+   Evas_Coord px, py;
 
-   size = g->tsize;
-   if ((gw != g->w) && (g->w > 0))
-     size = ((long long)gw * size) / g->w;
-   if (size < (g->tsize / 2)) return; // else we will load to much tiles
+   if (wd->paused_markers || (!eina_list_count(wd->markers))) return;
 
-   it = eina_matrixsparse_iterator_new(g->grid);
+   _pan_geometry_get(wd, &px, &py);
 
-   EINA_ITERATOR_FOREACH(it, cell)
-     {
-        gi = eina_matrixsparse_cell_data_get(cell);
+   _edj_marker_size_get(wd, &gw, &gh);
+   gw *= 2;
+   gh *= 2;
 
-        xx = gi->out.x;
-        yy = gi->out.y;
-        ww = gi->out.w;
-        hh = gi->out.h;
+   EINA_LIST_FOREACH(wd->markers, l, marker)
+     {
+        _marker_update(marker);
+        marker->grouped = EINA_FALSE;
+        marker->leader = EINA_FALSE;
+     }
 
-        if ((gw != g->w) && (g->w > 0))
-          {
-             tx = xx;
-             xx = ((long long )gw * xx) / g->w;
-             ww = (((long long)gw * (tx + ww)) / g->w) - xx;
-          }
-        if ((gh != g->h) && (g->h > 0))
+   EINA_LIST_FOREACH(wd->group_classes, l, group_clas)
+     {
+        Eina_List *ll;
+        EINA_LIST_FOREACH(group_clas->markers, ll, marker)
           {
-             ty = yy;
-             yy = ((long long)gh * yy) / g->h;
-             hh = (((long long)gh * (ty + hh)) / g->h) - yy;
-          }
+             Eina_List *lll;
+             Elm_Map_Marker *mm;
+             Eina_List *markers = NULL;
 
-        if (!ELM_RECTS_INTERSECT(xx - wd->pan_x + ox,
-                                 yy  - wd->pan_y + oy,
-                                 ww, hh,
-                                 cvx, cvy, cvw, cvh))
-          {
-             if (gi->file_have)
+             if (marker->grouped) continue;
+             if (group_clas->zoom_grouped < wd->zoom)
                {
-                  evas_object_hide(gi->img);
-                  //evas_object_hide(gi->txt);
-                  evas_object_image_file_set(gi->img, NULL, NULL);
+                  marker->grouped = EINA_FALSE;
+                  continue;
                }
-             else if (gi->job)
+
+             EINA_LIST_FOREACH(group_clas->markers, lll, mm)
                {
-                  DBG("Download abort %s", gi->file);
-                  ecore_file_download_abort(gi->job);
-                  ecore_file_remove(gi->file);
-                  gi->job = NULL;
-                  wd->try_num--;
+                  if (marker == mm || mm->grouped) continue;
+                  if (ELM_RECTS_INTERSECT(mm->x, mm->y, mm->w, mm->h,
+                                         marker->x, marker->y, gw, gh))
+                   {
+                      // mm is group follower.
+                      mm->leader = EINA_FALSE;
+                      mm->grouped = EINA_TRUE;
+                      markers = eina_list_append(markers, mm);
+                   }
                }
+              if (eina_list_count(markers) >= 1)
+                {
+                   // marker is group leader.
+                   marker->leader = EINA_TRUE;
+                   marker->grouped = EINA_TRUE;
+                   markers = eina_list_append(markers, marker);
+
+                   if (!marker->group) marker->group = _marker_group_create(wd);
+                   _marker_group_update(marker->group, group_clas, markers);
+                }
           }
      }
-   eina_iterator_free(it);
-
-   xx = wd->pan_x / size - 1;
-   if (xx < 0) xx = 0;
 
-   yy = wd->pan_y / size - 1;
-   if (yy < 0) yy = 0;
-
-   ww = ow / size + 2;
-   if (xx + ww >= g->gw) ww = g->gw - xx - 1;
+   EINA_LIST_FOREACH(wd->markers, l, marker)
+     {
 
-   hh = oh / size + 2;
-   if (yy + hh >= g->gh) hh = g->gh - yy - 1;
+        if (marker->grouped ||
+           (marker->group_clas &&
+            (marker->group_clas->hide ||
+             marker->group_clas->zoom_displayed > wd->zoom)))
+           evas_object_hide(marker->obj);
+        else
+          {
+             Evas_Coord x, y;
+             _coord_rotate(marker->x + px, marker->y + py, wd->rotate.cx,
+                           wd->rotate.cy, wd->rotate.d, &x, &y);
+             _obj_place(marker->obj, x - (marker->w / 2), y - (marker->h / 2),
+                         marker->w, marker->h);
+          }
+     }
 
-   for (y = yy; y <= yy + hh; y++)
+   EINA_LIST_FOREACH(wd->markers, l, marker)
      {
-        for (x = xx; x <= xx + ww; x++)
+        Marker_Group *group = marker->group;
+        if (!group) continue;
+
+        if (!marker->leader || (group->clas->hide) ||
+            (group->clas->zoom_displayed > wd->zoom))
+           evas_object_hide(group->obj);
+        else
           {
-             gi = eina_matrixsparse_data_idx_get(g->grid, y, x);
+             Evas_Coord x, y;
+             _coord_rotate(group->x + px, group->y + py, wd->rotate.cx,
+                           wd->rotate.cy, wd->rotate.d, &x, &y);
+             _obj_place(group->obj, x - (group->w / 2), y - (group->h / 2),
+                         group->w, group->h);
+          }
+     }
+}
 
-             if (!gi)
-               {
-                  char buf[PATH_MAX];
-                  char buf2[PATH_MAX];
-                  char *source;
-
-                  gi = calloc(1, sizeof(Grid_Item));
-                  EINA_SAFETY_ON_NULL_RETURN(gi);
-
-                  gi->wd = wd;
-                  gi->g = g;
-                  gi->zoom = g->zoom;
-                  gi->file_have = EINA_FALSE;
-                  gi->job = NULL;
-
-                  gi->src.x = x * g->tsize;
-                  gi->src.y = y * g->tsize;
-                  gi->src.w = g->tsize;
-                  gi->src.h = g->tsize;
-
-                  gi->out.x = gi->src.x;
-                  gi->out.y = gi->src.y;
-                  gi->out.w = gi->src.w;
-                  gi->out.h = gi->src.h;
-
-                  gi->img = evas_object_image_add(evas_object_evas_get(obj));
-                  evas_object_image_scale_hint_set(gi->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
-                  evas_object_image_filled_set(gi->img, 1);
-
-                  evas_object_smart_member_add(gi->img, wd->pan_smart);
-                  elm_widget_sub_object_add(obj, gi->img);
-                  evas_object_pass_events_set(gi->img, EINA_TRUE);
-                  evas_object_stack_below(gi->img, wd->sep_maps_markers);
-
-/*                gi->txt = evas_object_text_add(evas_object_evas_get(obj));
-                  evas_object_text_font_set(gi->txt, "Vera", 12);
-                  evas_object_color_set(gi->txt, 100, 100, 100, 255);
-                  evas_object_smart_member_add(gi->txt,
-                                               wd->pan_smart);
-                  elm_widget_sub_object_add(obj, gi->txt);
-                  evas_object_pass_events_set(gi->txt, EINA_TRUE);
-*/
-                  snprintf(buf, sizeof(buf), CACHE_PATH, wd->id, g->zoom, x);
-                  snprintf(buf2, sizeof(buf2), CACHE_FILE_PATH, buf, y);
-                  if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
 
-                  eina_stringshare_replace(&gi->file, buf2);
-                  source = wd->src->url_cb(obj, x, y, g->zoom);
-                  if ((!source) || (strlen(source)==0))
-                    {
-                       eina_stringshare_replace(&gi->source, NULL);
-                       WRN("Getting source url failed: %s", gi->file);
-                    }
-                  else eina_stringshare_replace(&gi->source, source);
-                  if (source) free(source);
+static void
+_grid_item_coord_get(Grid_Item *gi, int *x, int *y, int *w, int *h)
+{
+   EINA_SAFETY_ON_NULL_RETURN(gi);
 
-                  eina_matrixsparse_data_idx_set(g->grid, y, x, gi);
-               }
+   if (x) *x = gi->x * gi->wd->size.tile;
+   if (y) *y = gi->y * gi->wd->size.tile;
+   if (w) *w = gi->wd->size.tile;
+   if (h) *h = gi->wd->size.tile;
+}
 
-               if (gi->file_have)
-                 {
-                    DBG("File exists: %s", gi->file);
-                    _tile_update(gi);
-                 }
-               else if (!gi->job)
-                 {
-                    DBG("Added to download list: %s", gi->file);
-                    _add_download_list(obj, gi);
-                 }
-          }
-     }
+static Eina_Bool
+_grid_item_intersect(Grid_Item *gi)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(gi, EINA_FALSE);
+
+   Evas_Coord px, py;
+   Evas_Coord vw, vh;
+   Evas_Coord x, y, w, h;
+
+   _pan_geometry_get(gi->wd, &px, &py);
+   _viewport_size_get(gi->wd, &vw, &vh);
+   _grid_item_coord_get(gi, &x, &y, &w, &h);
+   return ELM_RECTS_INTERSECT(x + px, y + py, w, h, 0, 0, vw, vh);
 }
 
 static void
-_smooth_update(Evas_Object *obj)
+_grid_item_update(Grid_Item *gi)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Eina_List *l;
-   Grid *g;
+   evas_object_image_file_set(gi->img, gi->file, NULL);
+   if (!gi->wd->zoom_timer && !gi->wd->scr_timer)
+      evas_object_image_smooth_scale_set(gi->img, EINA_TRUE);
+   else evas_object_image_smooth_scale_set(gi->img, EINA_FALSE);
 
-   if (!wd) return;
-   EINA_LIST_FOREACH(wd->grids, l, g)
+   Evas_Load_Error err = evas_object_image_load_error_get(gi->img);
+   if (err != EVAS_LOAD_ERROR_NONE)
      {
-        Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
-        Eina_Matrixsparse_Cell *cell;
+        ERR("Image loading error (%s): %s", gi->file, evas_load_error_str(err));
+        ecore_file_remove(gi->file);
+        gi->file_have = EINA_FALSE;
+     }
+   else
+     {
+        Evas_Coord px, py;
+        Evas_Coord x, y, w, h;
 
-        EINA_ITERATOR_FOREACH(it, cell)
-          {
-             Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
-             evas_object_image_smooth_scale_set(gi->img, (!wd->nosmooth));
-          }
-        eina_iterator_free(it);
+        _pan_geometry_get(gi->wd, &px, &py);
+        _grid_item_coord_get(gi, &x, &y, &w, &h);
+
+        _obj_place(gi->img, x + px, y + py, w, h);
+        _obj_rotate(gi->wd, gi->img);
+        gi->file_have = EINA_TRUE;
      }
 }
 
-static Eina_Bool
-_scr_timeout(void *data)
+static void
+_grid_item_load(Grid_Item *gi)
 {
-   ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
-   Widget_Data *wd = elm_widget_data_get(data);
-
-   if (!wd) return ECORE_CALLBACK_CANCEL;
-   wd->nosmooth--;
-   if (!wd->nosmooth) _smooth_update(data);
-   wd->scr_timer = NULL;
-   return ECORE_CALLBACK_CANCEL;
+   EINA_SAFETY_ON_NULL_RETURN(gi);
+   if (gi->file_have) _grid_item_update(gi);
+   else if (!gi->job)
+     {
+        gi->wd->download_list = eina_list_remove(gi->wd->download_list, gi);
+        gi->wd->download_list = eina_list_append(gi->wd->download_list, gi);
+     }
 }
 
 static void
-_scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_grid_item_unload(Grid_Item *gi)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
+   EINA_SAFETY_ON_NULL_RETURN(gi);
+   if (gi->file_have)
+     {
+        evas_object_hide(gi->img);
+        evas_object_image_file_set(gi->img, NULL, NULL);
+     }
+   else if (gi->job)
+     {
+        ecore_file_download_abort(gi->job);
+        ecore_file_remove(gi->file);
+        gi->job = NULL;
+        gi->wd->try_num--;
+     }
+   else gi->wd->download_list = eina_list_remove(gi->wd->download_list, gi);
+
+}
+
+static Grid_Item *
+_grid_item_create(Grid *g, Evas_Coord x, Evas_Coord y)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL);
+   char buf[PATH_MAX];
+   char buf2[PATH_MAX];
+   char *source;
+   Grid_Item *gi;
+
+   gi = ELM_NEW(Grid_Item);
+   gi->wd = g->wd;
+   gi->g = g;
+   gi->x = x;
+   gi->y = y;
+
+   gi->file_have = EINA_FALSE;
+   gi->job = NULL;
+
+   gi->img = evas_object_image_add(evas_object_evas_get(g->wd->obj));
+   evas_object_image_smooth_scale_set(gi->img, EINA_FALSE);
+   evas_object_image_scale_hint_set(gi->img, EVAS_IMAGE_SCALE_HINT_DYNAMIC);
+   evas_object_image_filled_set(gi->img, 1);
+   evas_object_smart_member_add(gi->img, g->wd->pan_smart);
+   evas_object_pass_events_set(gi->img, EINA_TRUE);
+   evas_object_stack_below(gi->img, g->wd->sep_maps_markers);
 
-   if (!wd) return;
-   if (!wd->scr_timer)
+   snprintf(buf, sizeof(buf), CACHE_PATH, g->wd->id, g->zoom, x);
+   snprintf(buf2, sizeof(buf2), CACHE_FILE_PATH, buf, y);
+   if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
+
+   eina_stringshare_replace(&gi->file, buf2);
+   source = g->wd->src->url_cb(g->wd->obj, x, y, g->zoom);
+   if ((!source) || (!strlen(source)))
      {
-        wd->nosmooth++;
-        if (wd->nosmooth == 1) _smooth_update(data);
+        eina_stringshare_replace(&gi->source, NULL);
+        ERR("Getting source url failed: %s", gi->file);
      }
-   if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
-   wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
+   else eina_stringshare_replace(&gi->source, source);
+   if (source) free(source);
+   eina_matrixsparse_data_idx_set(g->grid, y, x, gi);
+   return gi;
 }
 
 static void
-zoom_do(Evas_Object *obj)
+_grid_item_free(Grid_Item *gi)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord xx, yy, ow, oh;
+   EINA_SAFETY_ON_NULL_RETURN(gi);
 
-   if (!wd) return;
-   wd->size.w = wd->size.nw;
-   wd->size.h = wd->size.nh;
+   _grid_item_unload(gi);
+   if (gi->g && gi->g->grid) eina_matrixsparse_data_idx_set(gi->g->grid,
+                                                            gi->y, gi->x, NULL);
+   if (gi->source) eina_stringshare_del(gi->source);
+   if (gi->file) eina_stringshare_del(gi->file);
+   if (gi->img) evas_object_del(gi->img);
+   if (gi->file_have) ecore_file_remove(gi->file);
+   free(gi);
+}
 
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
+static void
+_downloaded_cb(void *data, const char *file __UNUSED__, int status)
+{
+   Grid_Item *gi = data;
 
-   if (wd->center_on.enabled)
+   if (status == 200)
      {
-        elm_map_utils_convert_geo_into_coord(obj, wd->center_on.lon, wd->center_on.lat, wd->size.w, &xx, &yy);
-        xx -= ow / 2;
-        yy -= oh / 2;
+        DBG("Download success from %s to %s", gi->source, gi->file);
+        _grid_item_update(gi);
+        gi->wd->finish_num++;
      }
    else
      {
-        xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
-        yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
+        WRN("Download failed from %s to %s (%d) ", gi->source, gi->file, status);
+        ecore_file_remove(gi->file);
+        gi->file_have = EINA_FALSE;
      }
 
+   gi->job = NULL;
+   gi->wd->download_num--;
+   evas_object_smart_callback_call(gi->wd->obj, SIG_DOWNLOADED, NULL);
 
-   if (xx < 0) xx = 0;
-   else if (xx > (wd->size.w - ow)) xx = wd->size.w - ow;
-   if (yy < 0) yy = 0;
-   else if (yy > (wd->size.h - oh)) yy = wd->size.h - oh;
+   if (!gi->wd->download_num)
+     {
+        edje_object_signal_emit(elm_smart_scroller_edje_object_get(gi->wd->scr),
+                                "elm,state,busy,stop", "elm");
+        evas_object_smart_callback_call(gi->wd->obj, SIG_LOADED_DETAIL, NULL);
+     }
+}
+
+static Eina_Bool
+_download_job(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, ECORE_CALLBACK_CANCEL);
+   Widget_Data *wd = data;
 
-   wd->show.show = EINA_TRUE;
-   wd->show.x = xx;
-   wd->show.y = yy;
-   wd->show.w = ow;
-   wd->show.h = oh;
+   Eina_List *l, *ll;
+   Grid_Item *gi;
+
+   if (!eina_list_count(wd->download_list))
+     {
+        wd->download_idler = NULL;
+        return ECORE_CALLBACK_CANCEL;
+     }
+
+   EINA_LIST_REVERSE_FOREACH_SAFE(wd->download_list, l, ll, gi)
+     {
+        if (gi->g->zoom != wd->zoom || !_grid_item_intersect(gi))
+          {
+             wd->download_list = eina_list_remove(wd->download_list, gi);
+             continue;
+          }
+        if (wd->download_num >= MAX_CONCURRENT_DOWNLOAD)
+           return ECORE_CALLBACK_RENEW;
+
+        Eina_Bool ret = ecore_file_download_full(gi->source, gi->file,
+                                                 _downloaded_cb, NULL,
+                                                 gi, &(gi->job), wd->ua);
+        if ((!ret) || (!gi->job))
+           ERR("Can't start to download from %s to %s", gi->source, gi->file);
+        else
+          {
+             wd->download_list = eina_list_remove(wd->download_list, gi);
 
-   if (wd->calc_job) ecore_job_del(wd->calc_job);
-   wd->calc_job = ecore_job_add(_calc_job, wd);
+             wd->try_num++;
+             wd->download_num++;
+             if (wd->download_num == 1)
+               edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
+                                       "elm,state,busy,start", "elm");
+          }
+     }
+   return ECORE_CALLBACK_RENEW;
 }
 
-static Eina_Bool
-_zoom_timeout(void *data)
+static void
+_grid_viewport_get(Grid *g, int *x, int *y, int *w, int *h)
 {
-   ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
-   Widget_Data *wd = elm_widget_data_get(data);
+   EINA_SAFETY_ON_NULL_RETURN(g);
+   int xx, yy, ww, hh;
+   Evas_Coord px, py, vw, vh;
 
-   if (!wd) return ECORE_CALLBACK_CANCEL;
-   wd->zoom_timer = NULL;
-   wd->pinch.level = 1.0;
-   zoom_do(data);
-   evas_object_smart_callback_call(data, SIG_ZOOM_STOP, NULL);
-   return ECORE_CALLBACK_CANCEL;
+   _pan_geometry_get(g->wd, &px, &py);
+   _viewport_size_get(g->wd, &vw, &vh);
+   if (px > 0) px = 0;
+   if (py > 0) py = 0;
+
+   xx = (-px / g->wd->size.tile) - 1;
+   if (xx < 0) xx = 0;
+
+   yy = (-py / g->wd->size.tile) - 1;
+   if (yy < 0) yy = 0;
+
+   ww = (vw / g->wd->size.tile) + 3;
+   if (xx + ww >= g->tw) ww = g->tw - xx;
+
+   hh = (vh / g->wd->size.tile) + 3;
+   if (yy + hh >= g->th) hh = g->th - yy;
+
+   if (x) *x = xx;
+   if (y) *y = yy;
+   if (w) *w = ww;
+   if (h) *h = hh;
 }
 
-static Eina_Bool
-_zoom_anim(void *data)
+static void
+_grid_unload(Grid *g)
 {
-   ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
-   Evas_Object *obj = data;
-   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(g);
+   Eina_Iterator *it;
+   Eina_Matrixsparse_Cell *cell;
+   Grid_Item *gi;
 
-   if (!wd) return ECORE_CALLBACK_CANCEL;
-   if (wd->zoom_method == ZOOM_METHOD_IN) wd->t += 0.1 ;
-   else if (wd->zoom_method == ZOOM_METHOD_OUT) wd->t -= 0.05;
-   else
+   it = eina_matrixsparse_iterator_new(g->grid);
+   EINA_ITERATOR_FOREACH(it, cell)
      {
-        wd->zoom_animator = NULL;
-        zoom_do(obj);
-        evas_object_smart_callback_call(data, SIG_ZOOM_STOP, NULL);
-        return ECORE_CALLBACK_CANCEL;
+        gi = eina_matrixsparse_cell_data_get(cell);
+        _grid_item_unload(gi);
      }
+   eina_iterator_free(it);
+}
 
-   if (wd->t >= 2.0)
+static void
+_grid_load(Grid *g)
+{
+   EINA_SAFETY_ON_NULL_RETURN(g);
+   int x, y, xx, yy, ww, hh;
+   Eina_Iterator *it;
+   Eina_Matrixsparse_Cell *cell;
+   Grid_Item *gi;
+
+   it = eina_matrixsparse_iterator_new(g->grid);
+   EINA_ITERATOR_FOREACH(it, cell)
      {
-        wd->zoom_animator = NULL;
-        wd->pinch.level = 2.0;
-        if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
-        wd->zoom_timer = ecore_timer_add(0.35, _zoom_timeout, obj);
-        return ECORE_CALLBACK_CANCEL;
+        gi = eina_matrixsparse_cell_data_get(cell);
+        if (!_grid_item_intersect(gi)) _grid_item_unload(gi);
      }
-   else if (wd->t <= 0.5)
+   eina_iterator_free(it);
+
+   _grid_viewport_get(g, &xx, &yy, &ww, &hh);
+   for (y = yy; y < yy + hh; y++)
      {
-        wd->zoom_animator = NULL;
-        wd->pinch.level = 0.5;
-        if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
-        wd->zoom_timer = ecore_timer_add(1.35, _zoom_timeout, obj);
-        return ECORE_CALLBACK_CANCEL;
+        for (x = xx; x < xx + ww; x++)
+          {
+             gi = eina_matrixsparse_data_idx_get(g->grid, y, x);
+             if (!gi) gi = _grid_item_create(g, x, y);
+             _grid_item_load(gi);
+          }
      }
-   else if (wd->t != 1.0)
+}
+
+static void
+_grid_place(Widget_Data *wd)
+{
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   Eina_List *l;
+   Grid *g;
+
+   EINA_LIST_FOREACH(wd->grids, l, g)
      {
-        Evas_Coord x, y, w, h;
-        float half_w, half_h;
-        evas_object_geometry_get(data, &x, &y, &w, &h);
-        half_w = (float)w * 0.5;
-        half_h = (float)h * 0.5;
-        wd->pinch.cx = x + half_w;
-        wd->pinch.cy = y + half_h;
-        wd->pinch.level = wd->t;
-        if (wd->calc_job) ecore_job_del(wd->calc_job);
-        wd->calc_job = ecore_job_add(_calc_job, wd);
+        if (wd->zoom == g->zoom) _grid_load(g);
+        else _grid_unload(g);
      }
-   return ECORE_CALLBACK_RENEW;
+  if (!wd->download_idler) wd->download_idler = ecore_idler_add(_download_job, wd);
 }
 
-static Eina_Bool
-_long_press(void *data)
+static void
+_grid_all_create(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
-   Widget_Data *wd = elm_widget_data_get(data);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN(wd->src);
 
-   if (!wd) return ECORE_CALLBACK_CANCEL;
-   wd->long_timer = NULL;
-   evas_object_smart_callback_call(data, SIG_LONGPRESSED, &wd->ev);
-   return ECORE_CALLBACK_CANCEL;
+   int zoom;
+   for (zoom = wd->src->zoom_min; zoom <= wd->src->zoom_max; zoom++)
+     {
+        Grid *g;
+        int tnum;
+        g = ELM_NEW(Grid);
+        g->wd = wd;
+        g->zoom = zoom;
+        tnum =  pow(2.0, g->zoom);
+        g->tw = tnum;
+        g->th = tnum;
+        g->grid = eina_matrixsparse_new(g->th, g->tw, NULL, NULL);
+        wd->grids = eina_list_append(wd->grids, g);
+     }
 }
 
 static void
-_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+_grid_all_clear(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
-   Evas_Event_Mouse_Down *ev = event_info;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (ev->button != 1) return;
-   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
-   else wd->on_hold = EINA_FALSE;
-   if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
-     evas_object_smart_callback_call(data, SIG_CLICKED_DOUBLE, ev);
-   else
-     evas_object_smart_callback_call(data, SIG_PRESS, ev);
-   if (wd->long_timer) ecore_timer_del(wd->long_timer);
-   wd->ev = *ev;
-   wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, data);
+   Grid *g;
+   EINA_LIST_FREE(wd->grids, g)
+     {
+        Grid_Item *gi;
+        Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
+        Eina_Matrixsparse_Cell *cell;
+        EINA_ITERATOR_FOREACH(it, cell)
+          {
+             gi = eina_matrixsparse_cell_data_get(cell);
+             if (gi) _grid_item_free(gi);
+          }
+        eina_iterator_free(it);
+
+        eina_matrixsparse_free(g->grid);
+        free(g);
+     }
+   if (!ecore_file_recursive_rm(CACHE_ROOT_PATH))
+      ERR("Deletion of %s failed", CACHE_ROOT_PATH);
 }
 
 static void
-_mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+_track_place(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
+#ifdef ELM_EMAP
    EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   Evas_Event_Mouse_Up *ev = event_info;
-   EINA_SAFETY_ON_NULL_RETURN(ev);
+   Eina_List *l;
+   Evas_Object *route;
+   int xmin, xmax, ymin, ymax;
+   Evas_Coord px, py, ow, oh;
+   px = wd->pan_x;
+   py = wd->pan_y;
+   _viewport_size_get(wd, &ow, &oh);
 
-   if (ev->button != 1) return;
-   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
-   else wd->on_hold = EINA_FALSE;
-   if (wd->long_timer)
+   Evas_Coord size = wd->size.w;
+
+   EINA_LIST_FOREACH(wd->track, l, route)
      {
-        ecore_timer_del(wd->long_timer);
-        wd->long_timer = NULL;
+        elm_map_utils_convert_geo_into_coord(wd->obj, elm_route_lon_min_get(route), elm_route_lat_max_get(route), size, &xmin, &ymin);
+        elm_map_utils_convert_geo_into_coord(wd->obj, elm_route_lon_max_get(route), elm_route_lat_min_get(route), size, &xmax, &ymax);
+
+        if( !(xmin < px && xmax < px) && !(xmin > px+ow && xmax > px+ow))
+        {
+           if( !(ymin < py && ymax < py) && !(ymin > py+oh && ymax > py+oh))
+           {
+              //display the route
+              evas_object_move(route, xmin - px + ox, ymin - py + oy);
+              evas_object_resize(route, xmax - xmin, ymax - ymin);
+
+              evas_object_raise(route);
+              _obj_rotate(wd->obj, route);
+              evas_object_show(route);
+
+              continue;
+           }
+        }
+        //the route is not display
+        evas_object_hide(route);
      }
-   if (!wd->on_hold) evas_object_smart_callback_call(data, SIG_CLICKED, ev);
-   wd->on_hold = EINA_FALSE;
+#else
+   (void) wd;
+#endif
 }
-
 static void
-_mouse_wheel_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+_route_place(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
    EINA_SAFETY_ON_NULL_RETURN(wd);
+   Eina_List *lr, *lp, *ln;
+   Path_Node *n;
+   Evas_Object *p;
+   Elm_Map_Route *r;
+   int nodes;
+   int x, y;
+   double a;
+   Evas_Coord ow, oh;
+   Evas_Coord px, py;
 
-   if (!wd->paused)
-     {
-        int zoom_diff = 0;
-        Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel*) event_info;
-        Evas_Coord x, y, w, h;
+   px = wd->pan_x;
+   py = wd->pan_y;
+   _viewport_size_get(wd, &ow, &oh);
 
-        evas_object_geometry_get(data, &x, &y, &w, &h);
+   Evas_Coord size = wd->size.w;
 
-        if (wd->calc_job) ecore_job_del(wd->calc_job);
-        wd->calc_job = ecore_job_add(_calc_job, wd);
+   EINA_LIST_FOREACH(wd->route, lr, r)
+     {
+        EINA_LIST_FOREACH(r->path, lp, p)
+          {
+             evas_object_polygon_points_clear(p);
+          }
 
-        wd->wheel_diff -= ev->z;
-        wd->pinch.level = wd->pinch.diff * pow(2.0, (double)wd->wheel_diff/10);
-        wd->pinch.cx = x + ((double)w * 0.5);
-        wd->pinch.cy = y + ((double)h * 0.5);
+        nodes = eina_list_count(r->nodes);
 
-        if (wd->pinch.level > 1.99 || wd->pinch.level < 1.01)
+        EINA_LIST_FOREACH(r->nodes, ln, n)
           {
-             wd->wheel_diff = 0;
-             if (wd->pinch.level > 1.99)
+             if ((!wd->zoom) || ((n->idx) &&
+                 ((n->idx % (int)ceil((double)nodes/(double)size*100.0))))) continue;
+             if (r->inbound)
                {
-                  zoom_diff = 1;
-                  wd->pinch.diff = wd->pinch.level / 2.0;
-                  wd->pinch.level = wd->pinch.level / 2.0;
+                  elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
+                  if ((x >= px - ow) && (x <= (px + ow*2)) &&
+                      (y >= py - oh) && (y <= (py + oh*2)))
+                    {
+                       x = x - px;
+                       y = y - py;
+
+                       p = eina_list_nth(r->path, n->idx);
+                       a = (double)(y - r->y) / (double)(x - r->x);
+                       if ((abs(a) >= 1) || (r->x == x))
+                         {
+                            evas_object_polygon_point_add(p, r->x - 3, r->y);
+                            evas_object_polygon_point_add(p, r->x + 3, r->y);
+                            evas_object_polygon_point_add(p, x + 3, y);
+                            evas_object_polygon_point_add(p, x - 3, y);
+                         }
+                       else
+                         {
+                            evas_object_polygon_point_add(p, r->x, r->y - 3);
+                            evas_object_polygon_point_add(p, r->x, r->y + 3);
+                            evas_object_polygon_point_add(p, x, y + 3);
+                            evas_object_polygon_point_add(p, x, y - 3);
+                         }
+
+                       evas_object_color_set(p, r->color.r, r->color.g, r->color.b, r->color.a);
+                       evas_object_raise(p);
+                       _obj_rotate(wd, p);
+                       evas_object_show(p);
+                       r->x = x;
+                       r->y = y;
+                    }
+                  else r->inbound = EINA_FALSE;
                }
-             else if (wd->pinch.level < 1.01)
+             else
                {
-                  zoom_diff = -1;
-                  wd->pinch.diff = wd->pinch.level * 2.0;
-                  wd->pinch.level = wd->pinch.level * 2.0;
+                  elm_map_utils_convert_geo_into_coord(wd->obj, n->pos.lon, n->pos.lat, size, &x, &y);
+                  if ((x >= px - ow) && (x <= (px + ow*2)) &&
+                      (y >= py - oh) && (y <= (py + oh*2)))
+                    {
+                       r->x = x - px;
+                       r->y = y - py;
+                       r->inbound = EINA_TRUE;
+                    }
+                  else r->inbound = EINA_FALSE;
                }
-
-             Elm_Map_Zoom_Mode temp;
-             temp = wd->mode;
-             wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
-             wd->paused = EINA_TRUE;
-             elm_map_zoom_set(data, wd->zoom + zoom_diff);
-             wd->paused = EINA_FALSE;
-             wd->mode = temp;
-          }
-        else
-          {
-             if (wd->calc_job) ecore_job_del(wd->calc_job);
-             wd->calc_job = ecore_job_add(_calc_job, wd);
           }
+          r->inbound = EINA_FALSE;
      }
 }
 
 static void
-_rect_resize_cb(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_delayed_do(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(data, widtype);
-   Widget_Data *wd = elm_widget_data_get(data);
-   int x, y, w, h;
-
-   evas_object_geometry_get(wd->rect, &x, &y, &w, &h);
-   evas_object_geometry_get(wd->pan_smart, &x, &y, &w, &h);
-   evas_object_resize(wd->rect, w, h);
-   evas_object_move(wd->rect, x, y);
+   Delayed_Data *dd;
+   dd = eina_list_nth(wd->delayed_jobs, 0);
+   if (dd && !dd->wd->zoom_animator)
+     {
+        dd->func(dd);
+        wd->delayed_jobs = eina_list_remove(wd->delayed_jobs, dd);
+        free(dd);
+     }
 }
 
 static void
-_del_hook(Evas_Object *obj)
+_smooth_update(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Elm_Map_Group_Class *group_clas;
-   Elm_Map_Marker_Class *marker_clas;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
    Eina_List *l;
-   Evas_Object *p;
-   Path_Node *n;
-   Path_Waypoint *w;
-   Ecore_Event_Handler *h;
-   Elm_Map_Route *r;
-   Elm_Map_Name *na;
-   Evas_Object *route;
-
-   if (!wd) return;
-   EINA_LIST_FREE(wd->groups_clas, group_clas)
-     {
-        if (group_clas->style)
-          eina_stringshare_del(group_clas->style);
-        free(group_clas);
-     }
+   Grid *g;
 
-   EINA_LIST_FREE(wd->markers_clas, marker_clas)
+   EINA_LIST_FOREACH(wd->grids, l, g)
      {
-        if (marker_clas->style)
-          eina_stringshare_del(marker_clas->style);
-        free(marker_clas);
-     }
+        Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
+        Eina_Matrixsparse_Cell *cell;
 
-   EINA_LIST_FOREACH(wd->route, l, r)
-     {
-        EINA_LIST_FREE(r->path, p)
+        EINA_ITERATOR_FOREACH(it, cell)
           {
-             evas_object_del(p);
+             Grid_Item *gi = eina_matrixsparse_cell_data_get(cell);
+             if (_grid_item_intersect(gi))
+                evas_object_image_smooth_scale_set(gi->img, EINA_TRUE);
           }
+        eina_iterator_free(it);
+     }
+}
 
-        EINA_LIST_FREE(r->waypoint, w)
-          {
-             if (w->point) eina_stringshare_del(w->point);
-             free(w);
-          }
+static Eina_Bool
+_zoom_timeout(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, ECORE_CALLBACK_CANCEL);
+   Widget_Data *wd = data;
+   _smooth_update(wd);
+   wd->zoom_timer = NULL;
+   evas_object_smart_callback_call(wd->obj, SIG_ZOOM_STOP, NULL);
+  return ECORE_CALLBACK_CANCEL;
+}
 
-        EINA_LIST_FREE(r->nodes, n)
-          {
-             if (n->pos.address) eina_stringshare_del(n->pos.address);
-             free(n);
-          }
+static void
+zoom_do(Widget_Data *wd, double zoom)
+{
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   if (zoom > wd->zoom_max) zoom = wd->zoom_max;
+   else if (zoom < wd->zoom_min) zoom = wd->zoom_min;
 
-        EINA_LIST_FREE(r->handlers, h)
-          {
-             ecore_event_handler_del(h);
-          }
+   Evas_Coord px, py, vw, vh;
+   Evas_Coord ow, oh;
 
-        if (r->con_url) ecore_con_url_free(r->con_url);
-        if (r->info.nodes) eina_stringshare_del(r->info.nodes);
-        if (r->info.waypoints) eina_stringshare_del(r->info.waypoints);
-     }
+   wd->zoom = ROUND(zoom);
+   wd->zoom_detail = zoom;
+   ow = wd->size.w;
+   oh = wd->size.h;
+   wd->size.tile = pow(2.0, (zoom - wd->zoom)) * wd->tsize;
+   wd->size.w = pow(2.0, wd->zoom) * wd->size.tile;
+   wd->size.h = wd->size.w;;
+
+   // Fix to zooming with (viewport center px, py) as the center to prevent
+   // from zooming with (0,0) as the cetner. (scroller default behavior)
+   _pan_geometry_get(wd, &px, &py);
+   _viewport_size_get(wd, &vw, &vh);
+   if ((vw > 0) && (vh > 0) && (ow > 0) && (oh > 0))
+     {
+        Evas_Coord xx, yy;
+        double sx, sy;
+        if (vw > ow) sx = 0.5;
+        else         sx = (double)(-px + (vw / 2)) / ow;
+        if (vh > oh) sy = 0.5;
+        else         sy = (double)(-py + (vh / 2)) / oh;
+
+        if (sx > 1.0) sx = 1.0;
+        if (sy > 1.0) sy = 1.0;
+
+        xx = (sx * wd->size.w) - (vw / 2);
+        yy = (sy * wd->size.h) - (vh / 2);
+        if (xx < 0) xx = 0;
+        else if (xx > (wd->size.w - vw)) xx = wd->size.w - vw;
+        if (yy < 0) yy = 0;
+        else if (yy > (wd->size.h - vh)) yy = wd->size.h - vh;
+        elm_smart_scroller_child_region_show(wd->scr, xx, yy, vw, vh);
+     }
+
+   if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
+   else evas_object_smart_callback_call(wd->obj, SIG_ZOOM_START, NULL);
+   wd->zoom_timer = ecore_timer_add(0.25, _zoom_timeout, wd);
+   evas_object_smart_callback_call(wd->obj, SIG_ZOOM_CHANGE, NULL);
+
+   evas_object_smart_callback_call(wd->pan_smart, SIG_CHANGED, NULL);
+   evas_object_smart_changed(wd->pan_smart);
+}
 
-   EINA_LIST_FREE(wd->names, na)
+static Eina_Bool
+_zoom_anim(void *data)
+{
+   Widget_Data *wd = data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, ECORE_CALLBACK_CANCEL);
+
+   if (wd->ani.cnt <= 0)
      {
-        if (na->address) free(na->address);
-        if (na->handler) ecore_event_handler_del(na->handler);
-        if (na->ud.fname)
-          {
-             ecore_file_remove(na->ud.fname);
-             free(na->ud.fname);
-             na->ud.fname = NULL;
-          }
+        wd->zoom_animator = NULL;
+        evas_object_smart_changed(wd->pan_smart);
+        return ECORE_CALLBACK_CANCEL;
      }
-
-   EINA_LIST_FREE(wd->track, route)
+   else
      {
-        evas_object_del(route);
+        wd->ani.zoom += wd->ani.diff;
+        wd->ani.cnt--;
+        zoom_do(wd, wd->ani.zoom);
+        return ECORE_CALLBACK_RENEW;
      }
+}
 
-   if (wd->map) evas_map_free(wd->map);
-   if (wd->source_names) free(wd->source_names);
-   if (wd->calc_job) ecore_job_del(wd->calc_job);
-   if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
-   if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
-   if (wd->long_timer) ecore_timer_del(wd->long_timer);
-   if (wd->user_agent) eina_stringshare_del(wd->user_agent);
-   if (wd->ua) eina_hash_free(wd->ua);
-   if (wd->markers) free(wd->markers);
+static void
+zoom_with_animation(Widget_Data *wd, double zoom, int cnt)
+{
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   if (cnt == 0) return;
 
-   free(wd);
+   wd->ani.cnt = cnt;
+   wd->ani.zoom = wd->zoom;
+   wd->ani.diff = (double)(zoom - wd->zoom) / cnt;
+   if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
+   wd->zoom_animator = ecore_animator_add(_zoom_anim, wd);
 }
 
 static void
-_del_pre_hook(Evas_Object *obj)
+_sizing_eval(Widget_Data *wd)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Marker_Group *group;
-   Elm_Map_Marker *marker;
-   int i;
-   Eina_Bool free_marker = EINA_TRUE;
-   Eina_List *l;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
-   grid_clear_all(obj);
-   for (i = 0; i <= wd->zoom_max; i++)
-     {
-        if (!wd->markers[i]) continue;
-        Eina_Iterator *it = eina_matrixsparse_iterator_new(wd->markers[i]);
-        Eina_Matrixsparse_Cell *cell;
+   Evas_Coord maxw = -1, maxh = -1;
 
-        EINA_ITERATOR_FOREACH(it, cell)
-          {
-             l =  eina_matrixsparse_cell_data_get(cell);
-             EINA_LIST_FREE(l, group)
-               {
-                  EINA_LIST_FREE(group->markers, marker)
-                    {
-                       evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                                           _bubble_sc_hints_changed_cb, group);
-                       if (free_marker) free(marker);
-                    }
-                  free(group);
-               }
-             free_marker = EINA_FALSE;
-          }
-        eina_iterator_free(it);
-        eina_matrixsparse_free(wd->markers[i]);
-     }
+   evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
+   evas_object_size_hint_max_set(wd->obj, maxw, maxh);
+}
+
+static void
+_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   _sizing_eval(data);
+}
 
-   evas_object_del(wd->sep_maps_markers);
-   evas_object_del(wd->pan_smart);
-   wd->pan_smart = NULL;
+static Eina_Bool
+_scr_timeout(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, ECORE_CALLBACK_CANCEL);
+   Widget_Data *wd = data;
+   _smooth_update(wd);
+   wd->scr_timer = NULL;
+   evas_object_smart_callback_call(wd->obj, SIG_SCROLL_DRAG_STOP, NULL);
+   return ECORE_CALLBACK_CANCEL;
 }
 
 static void
-_on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
+_scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
 
-   if (!wd) return;
-   if (elm_widget_focus_get(obj))
-     {
-        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm");
-        evas_object_focus_set(wd->obj, EINA_TRUE);
-     }
-   else
-     {
-        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm");
-        evas_object_focus_set(wd->obj, EINA_FALSE);
-     }
+   if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
+   else evas_object_smart_callback_call(wd->obj, SIG_SCROLL_DRAG_START, NULL);
+   wd->scr_timer = ecore_timer_add(0.25, _scr_timeout, wd);
+   evas_object_smart_callback_call(wd->obj, SIG_SCROLL, NULL);
 }
 
 static void
-_theme_hook(Evas_Object *obj)
+_scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   evas_object_smart_callback_call(wd->obj, "scroll,anim,start", NULL);
+}
 
-   if (!wd) return;
-   elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", elm_widget_style_get(obj));
-   //   edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
-   _sizing_eval(obj);
+static void
+_scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   evas_object_smart_callback_call(wd->obj, "scroll,anim,stop", NULL);
+}
+
+static Eina_Bool
+_long_press(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, ECORE_CALLBACK_CANCEL);
+   Widget_Data *wd = data;
+
+   wd->long_timer = NULL;
+   evas_object_smart_callback_call(wd->obj, SIG_LONGPRESSED, &wd->ev);
+   return ECORE_CALLBACK_CANCEL;
 }
 
 static void
-_sizing_eval(Evas_Object *obj)
+_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   Evas_Event_Mouse_Down *ev = event_info;
 
-   if (!wd) return;
-   evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
-   evas_object_size_hint_min_set(obj, minw, minh);
-   evas_object_size_hint_max_set(obj, maxw, maxh);
+   if (ev->button != 1) return;
+
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
+   else wd->on_hold = EINA_FALSE;
+
+   if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
+     evas_object_smart_callback_call(wd->obj, SIG_CLICKED_DOUBLE, ev);
+   else evas_object_smart_callback_call(wd->obj, SIG_PRESS, ev);
+
+   if (wd->long_timer) ecore_timer_del(wd->long_timer);
+   wd->ev = *ev;
+   wd->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, wd);
 }
 
 static void
-_calc_job(void *data)
+_mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
 {
+   EINA_SAFETY_ON_NULL_RETURN(data);
    Widget_Data *wd = data;
-   Evas_Coord minw, minh;
 
-   if (!wd) return;
-   minw = wd->size.w;
-   minh = wd->size.h;
-   if (wd->resized)
+   Evas_Event_Mouse_Up *ev = event_info;
+   EINA_SAFETY_ON_NULL_RETURN(ev);
+
+   if (ev->button != 1) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
+   else wd->on_hold = EINA_FALSE;
+   if (wd->long_timer)
      {
-        wd->resized = EINA_FALSE;
-        if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
-          {
-             double tz = wd->zoom;
-             wd->zoom = 0.0;
-             elm_map_zoom_set(wd->obj, tz);
-          }
+        ecore_timer_del(wd->long_timer);
+        wd->long_timer = NULL;
      }
-   if ((minw != wd->minw) || (minh != wd->minh))
+   if (!wd->on_hold) evas_object_smart_callback_call(wd->obj, SIG_CLICKED, ev);
+   wd->on_hold = EINA_FALSE;
+}
+
+static void
+_mouse_wheel_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+
+   if (!wd->paused)
      {
-        wd->minw = minw;
-        wd->minh = minh;
-        evas_object_smart_callback_call(wd->pan_smart, SIG_CHANGED, NULL);
-        _sizing_eval(wd->obj);
-     }
-   wd->calc_job = NULL;
-   evas_object_smart_changed(wd->pan_smart);
+        Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel*) event_info;
+        zoom_do(wd, wd->zoom_detail - ((double)ev->z / 10));
+    }
 }
 
 static void
 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
 {
    Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
+   EINA_SAFETY_ON_NULL_RETURN(sd);
    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
+
    sd->wd->pan_x = x;
    sd->wd->pan_y = y;
    evas_object_smart_changed(obj);
@@ -1941,7 +1842,7 @@ static void
 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
 {
    Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
+   EINA_SAFETY_ON_NULL_RETURN(sd);
    if (x) *x = sd->wd->pan_x;
    if (y) *y = sd->wd->pan_y;
 }
@@ -1950,12 +1851,12 @@ static void
 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
 {
    Pan *sd = evas_object_smart_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(sd);
    Evas_Coord ow, oh;
-   if (!sd) return;
    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   ow = sd->wd->minw - ow;
+   ow = sd->wd->size.w - ow;
+   oh = sd->wd->size.h - oh;
    if (ow < 0) ow = 0;
-   oh = sd->wd->minh - oh;
    if (oh < 0) oh = 0;
    if (x) *x = ow;
    if (y) *y = oh;
@@ -1972,9 +1873,9 @@ static void
 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
 {
    Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
-   if (w) *w = sd->wd->minw;
-   if (h) *h = sd->wd->minh;
+   EINA_SAFETY_ON_NULL_RETURN(sd);
+   if (w) *w = sd->wd->size.w;
+   if (h) *h = sd->wd->size.h;
 }
 
 static void
@@ -1982,431 +1883,229 @@ _pan_add(Evas_Object *obj)
 {
    Pan *sd;
    Evas_Object_Smart_Clipped_Data *cd;
-   _pan_sc.add(obj);
+   parent_sc.add(obj);
    cd = evas_object_smart_data_get(obj);
-   if (!cd) return;
-   sd = calloc(1, sizeof(Pan));
-   if (!sd) return;
+   EINA_SAFETY_ON_NULL_RETURN(cd);
+   sd = ELM_NEW(Pan);
    sd->__clipped_data = *cd;
    free(cd);
    evas_object_smart_data_set(obj, sd);
 }
 
 static void
-_pan_del(Evas_Object *obj)
+_pan_resize(Evas_Object *obj, Evas_Coord w __UNUSED__, Evas_Coord h __UNUSED__)
 {
    Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
-   _pan_sc.del(obj);
-}
+   EINA_SAFETY_ON_NULL_RETURN(sd);
 
-static void
-_pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
-{
-   Pan *sd = evas_object_smart_data_get(obj);
-   Evas_Coord ow, oh;
-   if (!sd) return;
-   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
-   if ((ow == w) && (oh == h)) return;
-   sd->wd->resized = EINA_TRUE;
-   if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
-   sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
+   _sizing_eval(sd->wd);
+   elm_map_zoom_mode_set(sd->wd->obj, sd->wd->mode);
+   evas_object_smart_changed(obj);
 }
 
 static void
 _pan_calculate(Evas_Object *obj)
 {
    Pan *sd = evas_object_smart_data_get(obj);
-   Evas_Coord ox, oy, ow, oh;
-   Eina_List *l;
-   Grid *g;
-
    EINA_SAFETY_ON_NULL_RETURN(sd);
-   EINA_SAFETY_ON_NULL_RETURN(sd->wd);
-
-   evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
-   rect_place(sd->wd->obj, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
-   EINA_LIST_FOREACH(sd->wd->grids, l, g)
-     {
-        if (sd->wd->zoom == g->zoom) grid_load(sd->wd->obj, g);
-        else if (sd->wd->zoom-1 != g->zoom && sd->wd->zoom+1 != g->zoom) grid_unload(sd->wd->obj, g); // remain only adjacent grids
-        grid_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
-        if (sd->wd->zoom == g->zoom) marker_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
-        if (!sd->wd->zoom_animator) route_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
-        if (!sd->wd->zoom_animator) track_place(sd->wd->obj, g, sd->wd->pan_x, sd->wd->pan_y, ox, oy, ow, oh);
-     }
-}
-
-static void
-_pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
-{
-   Pan *sd = evas_object_smart_data_get(obj);
-   if (!sd) return;
-   if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
-   sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
-}
-
-static void
-_hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
-{
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
 
-   if (!wd) return;
-   elm_smart_scroller_hold_set(wd->scr, 1);
-}
-
-static void
-_hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
-{
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
+   Evas_Coord w, h;
+   evas_object_geometry_get(sd->wd->pan_smart, NULL, NULL, &w, &h);
+   if (w <= 0 || h <= 0) return;
 
-   if (!wd) return;
-   elm_smart_scroller_hold_set(wd->scr, 0);
+   _grid_place(sd->wd);
+   _marker_place(sd->wd);
+   _route_place(sd->wd);
+   _track_place(sd->wd);
+   _delayed_do(sd->wd);
 }
 
 static void
-_freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   elm_smart_scroller_freeze_set(wd->scr, 1);
+   EINA_SAFETY_ON_NULL_RETURN(obj);
+   evas_object_smart_changed(obj);
 }
 
 static void
-_freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_hold_on(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   elm_smart_scroller_freeze_set(wd->scr, 0);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   elm_smart_scroller_hold_set(wd->scr, 1);
 }
 
 static void
-_scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_hold_off(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   evas_object_smart_callback_call(data, "scroll,anim,start", NULL);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   elm_smart_scroller_hold_set(wd->scr, 0);
 }
 
 static void
-_scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_freeze_on(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   evas_object_smart_callback_call(data, "scroll,anim,stop", NULL);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   elm_smart_scroller_freeze_set(wd->scr, 1);
 }
 
 static void
-_scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_freeze_off(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(data);
-   EINA_SAFETY_ON_NULL_RETURN(wd);
-   wd->center_on.enabled = EINA_FALSE;
-
-   // FIXME: els_scoller sometimes give start event again & again... it confuses app. (els_scr bug?)
-   if (!wd->scr_started)
-     {
-        wd->scr_started = EINA_TRUE;
-        evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
-     }
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Widget_Data *wd = data;
+   elm_smart_scroller_freeze_set(wd->scr, 0);
 }
 
 static void
-_scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(data);
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
    EINA_SAFETY_ON_NULL_RETURN(wd);
-   wd->center_on.enabled = EINA_FALSE;
 
-   // FIXME: els_scoller sometimes give start event again & again... it confuses app. (els_scr bug?)
-   if (wd->scr_started)
+   if (elm_widget_focus_get(obj))
+     {
+        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm");
+        evas_object_focus_set(wd->obj, EINA_TRUE);
+     }
+   else
      {
-        wd->scr_started = EINA_FALSE;
-        evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
+        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm");
+        evas_object_focus_set(wd->obj, EINA_FALSE);
      }
 }
 
 static void
-_scr_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_del_hook(Evas_Object *obj)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
-}
-
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-static void
-_group_object_create(Marker_Group *group)
-{
-   const char *style = "radio";
-   Evas_Object *icon = NULL;
+   Eina_List *l, *ll;
+   Evas_Object *p;
+   Path_Node *n;
+   Path_Waypoint *w;
+   Ecore_Event_Handler *h;
+   Elm_Map_Route *r;
+   Elm_Map_Name *na;
+   Evas_Object *route;
+   Elm_Map_Marker *marker;
+   Elm_Map_Group_Class *group_clas;
+   Elm_Map_Marker_Class *clas;
+   Delayed_Data *dd;
+   int idx = 0;
+   Map_Sources_Tab *s;
 
-   if (group->obj) return;
-   if ((!group->clas->priv.objs_notused) || (eina_list_count(group->markers) == 1))
+   EINA_LIST_FOREACH(wd->route, l, r)
      {
-        //set icon and style
-        if (eina_list_count(group->markers) == 1)
+        EINA_LIST_FREE(r->path, p)
           {
-             Elm_Map_Marker *m = eina_list_data_get(group->markers);
-             if (m->clas->style)
-               style = m->clas->style;
-
-             if (m->clas->func.icon_get)
-               icon = m->clas->func.icon_get(group->wd->obj, m, m->data);
-
-             group->delete_object = EINA_TRUE;
+             evas_object_del(p);
           }
-        else
-          {
-             if (group->clas->style)
-               style = group->clas->style;
-
-             if (group->clas->func.icon_get)
-               icon = group->clas->func.icon_get(group->wd->obj, group->clas->data);
 
-             group->delete_object = EINA_FALSE;
+        EINA_LIST_FREE(r->waypoint, w)
+          {
+             if (w->point) eina_stringshare_del(w->point);
+             free(w);
           }
 
-        group->obj = elm_layout_add(group->wd->obj);
-        elm_layout_theme_set(group->obj, "map/marker", style, elm_widget_style_get(group->wd->obj));
-
-        if (icon) elm_object_part_content_set(group->obj, "elm.icon", icon);
-
-        evas_object_smart_member_add(group->obj, group->wd->pan_smart);
-        elm_widget_sub_object_add(group->wd->obj, group->obj);
-        evas_object_stack_above(group->obj, group->wd->sep_maps_markers);
+        EINA_LIST_FREE(r->nodes, n)
+          {
+             if (n->pos.address) eina_stringshare_del(n->pos.address);
+             free(n);
+          }
 
-        if (!group->delete_object)
-          group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
-     }
-   else
-     {
-        group->delete_object = EINA_FALSE;
+        EINA_LIST_FREE(r->handlers, h)
+          {
+             ecore_event_handler_del(h);
+          }
 
-        group->obj = eina_list_data_get(group->clas->priv.objs_notused);
-        group->clas->priv.objs_used = eina_list_append(group->clas->priv.objs_used, group->obj);
-        group->clas->priv.objs_notused = eina_list_remove(group->clas->priv.objs_notused, group->obj);
-        evas_object_show(group->obj);
+        if (r->con_url) ecore_con_url_free(r->con_url);
+        if (r->info.nodes) eina_stringshare_del(r->info.nodes);
+        if (r->info.waypoints) eina_stringshare_del(r->info.waypoints);
      }
 
-   edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb, group);
-   edje_object_signal_callback_add(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb, group);
-
-   group->update_nbelems = EINA_TRUE;
-   group->update_resize = EINA_TRUE;
-   group->update_raise = EINA_TRUE;
-
-   if (group->open) _group_bubble_create(group);
-}
-
-static void
-_group_object_free(Marker_Group *group)
-{
-   if (!group->obj) return;
-   if (!group->delete_object)
+   EINA_LIST_FREE(wd->names, na)
      {
-        group->clas->priv.objs_notused = eina_list_append(group->clas->priv.objs_notused, group->obj);
-        group->clas->priv.objs_used = eina_list_remove(group->clas->priv.objs_used, group->obj);
-        evas_object_hide(group->obj);
-
-        edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "open", "elm", _group_open_cb);
-        edje_object_signal_callback_del(elm_layout_edje_get(group->obj), "bringin", "elm", _group_bringin_cb);
+        if (na->address) free(na->address);
+        if (na->handler) ecore_event_handler_del(na->handler);
+        if (na->ud.fname)
+          {
+             ecore_file_remove(na->ud.fname);
+             free(na->ud.fname);
+             na->ud.fname = NULL;
+          }
      }
-   else
-     evas_object_del(group->obj);
-
-   group->obj = NULL;
-   _group_bubble_free(group);
-}
-
-static void
-_group_bubble_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
-{
-   Marker_Group *group = data;
-
-   if (!evas_object_above_get(group->rect)) return;
-   evas_object_raise(group->bubble);
-   evas_object_raise(group->sc);
-   evas_object_raise(group->rect);
-}
-
-static void
-_group_bubble_create(Marker_Group *group)
-{
-   if (group->bubble) return;
-
-   group->wd->opened_bubbles = eina_list_append(group->wd->opened_bubbles, group);
-   group->bubble = edje_object_add(evas_object_evas_get(group->obj));
-   _elm_theme_object_set(group->wd->obj, group->bubble, "map", "marker_bubble",
-                         elm_widget_style_get(group->wd->obj));
-   evas_object_smart_member_add(group->bubble,
-                                group->wd->obj);
-   elm_widget_sub_object_add(group->wd->obj, group->bubble);
 
-   _group_bubble_content_free(group);
-   if (!_group_bubble_content_update(group))
+   EINA_LIST_FREE(wd->track, route)
      {
-        //no content, we can delete the bubble
-        _group_bubble_free(group);
-        return;
+        evas_object_del(route);
      }
 
-   group->rect = evas_object_rectangle_add(evas_object_evas_get(group->obj));
-   evas_object_color_set(group->rect, 0, 0, 0, 0);
-   evas_object_repeat_events_set(group->rect, EINA_TRUE);
-   evas_object_smart_member_add(group->rect, group->wd->obj);
-   elm_widget_sub_object_add(group->wd->obj, group->rect);
-
-   evas_object_event_callback_add(group->rect, EVAS_CALLBACK_MOUSE_UP, _group_bubble_mouse_up_cb, group);
-
-   _group_bubble_place(group);
-}
-
-static void _bubble_sc_hints_changed_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
-{
-   _group_bubble_place(data);
-}
-
-static int
-_group_bubble_content_update(Marker_Group *group)
-{
-   Eina_List *l;
-   Elm_Map_Marker *marker;
-   int i = 0;
 
-   if (!group->bubble) return 1;
+   EINA_LIST_FOREACH_SAFE(wd->markers, l, ll, marker)
+      elm_map_marker_remove(marker);
+   eina_list_free(wd->markers);
 
-   if (!group->sc)
+   EINA_LIST_FREE(wd->group_classes, group_clas)
      {
-        group->sc = elm_scroller_add(group->bubble);
-        elm_widget_style_set(group->sc, "map_bubble");
-        elm_scroller_content_min_limit(group->sc, EINA_FALSE, EINA_TRUE);
-        elm_scroller_policy_set(group->sc, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
-        elm_scroller_bounce_set(group->sc, _elm_config->thumbscroll_bounce_enable, EINA_FALSE);
-        edje_object_part_swallow(group->bubble, "elm.swallow.content", group->sc);
-        evas_object_show(group->sc);
-        evas_object_smart_member_add(group->sc,
-                                     group->wd->obj);
-        elm_widget_sub_object_add(group->wd->obj, group->sc);
-
-        group->bx = elm_box_add(group->bubble);
-        evas_object_size_hint_align_set(group->bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
-        evas_object_size_hint_weight_set(group->bx, 0.5, 0.5);
-        elm_box_horizontal_set(group->bx, EINA_TRUE);
-        evas_object_show(group->bx);
-
-        elm_object_content_set(group->sc, group->bx);
-
-        evas_object_event_callback_add(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                       _bubble_sc_hints_changed_cb, group);
+        eina_list_free(group_clas->markers);
+        if (group_clas->style) eina_stringshare_del(group_clas->style);
+        free(group_clas);
      }
 
-   EINA_LIST_FOREACH(group->markers, l, marker)
+   EINA_LIST_FREE(wd->marker_classes, clas)
      {
-        if (i >= group->wd->markers_max_num) break;
-        if ((!marker->content) && (marker->clas->func.get))
-          marker->content = marker->clas->func.get(group->wd->obj, marker, marker->data);
-        else if (marker->content)
-          elm_box_unpack(group->bx, marker->content);
-        if (marker->content)
-          {
-             elm_box_pack_end(group->bx, marker->content);
-             i++;
-          }
+        if (clas->style) eina_stringshare_del(clas->style);
+        free(clas);
      }
-   return i;
-}
 
-static void
-_group_bubble_content_free(Marker_Group *group)
-{
-   Eina_List *l;
-   Elm_Map_Marker *marker;
+   if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
+   if (wd->long_timer) ecore_timer_del(wd->long_timer);
 
-   if (!group->sc) return;
-   EINA_LIST_FOREACH(group->markers, l, marker)
-     {
-        if ((marker->content) && (marker->clas->func.del))
-          marker->clas->func.del(group->wd->obj, marker, marker->data, marker->content);
-        else if (marker->content)
-          evas_object_del(marker->content);
-        marker->content = NULL;
-     }
-   evas_object_del(group->sc);
-   group->sc = NULL;
-}
+   if (wd->delayed_jobs) EINA_LIST_FREE(wd->delayed_jobs, dd) free(dd);
 
-static void
-_group_bubble_free(Marker_Group *group)
-{
-   if (!group->bubble) return;
-   group->wd->opened_bubbles = eina_list_remove(group->wd->opened_bubbles, group);
-   evas_object_event_callback_del_full(group->sc, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                       _bubble_sc_hints_changed_cb, group);
-   evas_object_del(group->bubble);
-   evas_object_del(group->rect);
-   group->bubble = NULL;
-   _group_bubble_content_free(group);
-}
+   if (wd->user_agent) eina_stringshare_del(wd->user_agent);
+   if (wd->ua) eina_hash_free(wd->ua);
+   if (wd->download_idler) ecore_idler_del(wd->download_idler);
+   eina_list_free(wd->download_list);
 
-static void
-_group_bubble_place(Marker_Group *group)
-{
-   Evas_Coord x, y, w;
-   Evas_Coord xx, yy, ww, hh;
-   const char *s;
+   if (wd->zoom_timer) ecore_timer_del(wd->zoom_timer);
+   if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
 
-   if ((!group->bubble) || (!group->obj)) return;
+   _grid_all_clear(wd);
 
-   evas_object_geometry_get(group->obj, &x, &y, &w, NULL);
-   edje_object_size_min_calc(group->bubble, NULL, &hh);
+   for (idx = 0; wd->src_names[idx]; idx++)
+      eina_stringshare_del(wd->src_names[idx]);
 
-   s = edje_object_data_get(group->bubble, "size_w");
-   if (s) ww = atoi(s);
-   else ww = 0;
-   xx = x + w / 2 - ww / 2;
-   yy = y-hh;
+   EINA_LIST_FREE(wd->srcs, s) free(s);
 
-   evas_object_move(group->bubble, xx, yy);
-   evas_object_resize(group->bubble, ww, hh);
-   obj_rotate_zoom(group->wd->obj, group->bubble);
-   evas_object_show(group->bubble);
+   if (wd->map) evas_map_free(wd->map);
 
-   evas_object_move(group->rect, xx, yy);
-   evas_object_resize(group->rect, ww, hh);
-   obj_rotate_zoom(group->wd->obj, group->rect);
-   evas_object_show(group->rect);
+   free(wd);
 }
 
 static void
-_group_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
+_del_pre_hook(Evas_Object *obj)
 {
-   Marker_Group *group = data;
-   Elm_Map_Marker *marker = eina_list_data_get(group->markers);
-   if (!marker) return;
-   group->bringin = EINA_TRUE;
-   elm_map_geo_region_bring_in(group->wd->obj, marker->longitude, marker->latitude);
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 }
 
 static void
-_group_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
+_theme_hook(Evas_Object *obj)
 {
-   Marker_Group *group = data;
-
-   if (group->bringin)
-     {
-        group->bringin = EINA_FALSE;
-        return;
-     }
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (group->bubble)
-     {
-        group->open = EINA_FALSE;
-        _group_bubble_free(group);
-        return;
-     }
-   group->open = EINA_TRUE;
-   _group_bubble_create(group);
+   elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", elm_widget_style_get(obj));
+   _sizing_eval(wd);
 }
 
 static Eina_Bool
@@ -2414,17 +2113,12 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
 {
    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
    Widget_Data *wd = elm_widget_data_get(obj);
-   int zoom;
-   Evas_Coord x = 0;
-   Evas_Coord y = 0;
-   Evas_Coord step_x = 0;
-   Evas_Coord step_y = 0;
-   Evas_Coord v_w = 0;
-   Evas_Coord v_h = 0;
-   Evas_Coord page_x = 0;
-   Evas_Coord page_y = 0;
-
-   if (!wd) return EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
+
+   Evas_Coord x, y;
+   Evas_Coord vh;
+   Evas_Coord step_x, step_y, page_x, page_y;
+
    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
    Evas_Event_Key_Down *ev = event_info;
    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
@@ -2432,7 +2126,7 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
+   _viewport_size_get(wd, NULL, &vh);
 
    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
      {
@@ -2453,29 +2147,25 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
    else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior")))
      {
         if (page_y < 0)
-          y -= -(page_y * v_h) / 100;
+          y -= -(page_y * vh) / 100;
         else
           y -= page_y;
      }
    else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
      {
         if (page_y < 0)
-          y += -(page_y * v_h) / 100;
+          y += -(page_y * vh) / 100;
         else
           y += page_y;
      }
    else if (!strcmp(ev->keyname, "KP_Add"))
      {
-        zoom = elm_map_zoom_get(obj) + 1;
-        elm_map_zoom_mode_set(obj, ELM_MAP_ZOOM_MODE_MANUAL);
-        elm_map_zoom_set(obj, zoom);
+        zoom_with_animation(wd, wd->zoom + 1, 10);
         return EINA_TRUE;
      }
    else if (!strcmp(ev->keyname, "KP_Subtract"))
      {
-        zoom = elm_map_zoom_get(obj) - 1;
-        elm_map_zoom_mode_set(obj, ELM_MAP_ZOOM_MODE_MANUAL);
-        elm_map_zoom_set(obj, zoom);
+        zoom_with_animation(wd, wd->zoom - 1, 10);
         return EINA_TRUE;
      }
    else return EINA_FALSE;
@@ -2498,7 +2188,6 @@ cb_dump_name_attrs(void *data, const char *key, const char *value)
    return EINA_TRUE;
 }
 
-
 static Eina_Bool
 cb_route_dump(void *data, Eina_Simple_XML_Type type, const char *value, unsigned offset __UNUSED__, unsigned length)
 {
@@ -2623,7 +2312,7 @@ _parse_kml(void *data)
              eina_stringshare_replace(&r->info.waypoints, dump.description);
              str = eina_str_split_full(dump.description, "\n", 0, &ele);
              r->info.waypoint_count = ele;
-             for (idx = 0 ; idx < ele ; idx++)
+             for (idx = 0; idx < ele; idx++)
                {
                   Path_Waypoint *wp = ELM_NEW(Path_Waypoint);
                   if (wp)
@@ -2647,7 +2336,7 @@ _parse_kml(void *data)
              eina_stringshare_replace(&r->info.nodes, dump.coordinates);
              str = eina_str_split_full(dump.coordinates, "\n", 0, &ele);
              r->info.node_count = ele;
-             for (idx = 0 ; idx < ele ; idx++)
+             for (idx = 0; idx < ele; idx++)
                {
                   sscanf(str[idx], "%lf,%lf", &lon, &lat);
                   Path_Node *n = ELM_NEW(Path_Node);
@@ -2750,14 +2439,8 @@ _route_complete_cb(void *data, int ev_type __UNUSED__, void *event)
    if (r->ud.fd) fclose(r->ud.fd);
    _parse_kml(r);
 
-   if (wd->grids)
-     {
-        Grid *g;
-        Evas_Coord ox, oy, ow, oh;
-        evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
-        g = _get_current_grid(wd);
-        route_place(wd->obj, g, wd->pan_x, wd->pan_y, ox, oy, ow, oh);
-     }
+   _route_place(wd);
+
    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
                            "elm,state,busy,stop", "elm");
    evas_object_smart_callback_call(wd->obj, SIG_ROUTE_LOADED, NULL);
@@ -2796,7 +2479,6 @@ _utils_convert_name(const Evas_Object *obj, int method, char *address, double lo
 
    if ((!wd) || (!wd->src)) return NULL;
    Elm_Map_Name *name = ELM_NEW(Elm_Map_Name);
-   if (!name) return NULL;
 
    snprintf(buf, sizeof(buf), DEST_NAME_XML_FILE);
    fd = mkstemp(buf);
@@ -2845,189 +2527,338 @@ _utils_convert_name(const Evas_Object *obj, int method, char *address, double lo
 }
 
 static Evas_Event_Flags
-zoom_start_cb(void *data, void *event_info __UNUSED__)
+_pinch_zoom_start_cb(void *data, void *event_info __UNUSED__)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, EVAS_EVENT_FLAG_NONE);
+   Widget_Data *wd = data;
+
+   wd->pinch_zoom = wd->zoom_detail;
+   return EVAS_EVENT_FLAG_NONE;
+}
+
+static Evas_Event_Flags
+_pinch_zoom_cb(void *data, void *event_info)
 {
    Widget_Data *wd = data;
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
 
-   // FIXME: scroller can be jumping strangely when resizing & scrolling at the sametime (els_scr bug?)
-   elm_smart_scroller_hold_set(wd->scr, 1);
-   elm_smart_scroller_freeze_set(wd->scr, 1);
-   _scr_drag_start(wd->obj, NULL, NULL);
+   if (!wd->paused)
+     {
+        Elm_Gesture_Zoom_Info *ei = event_info;
+        zoom_do(wd, wd->pinch_zoom + ei->zoom - 1);
+     }
+   return EVAS_EVENT_FLAG_NONE;
+}
+
+static Evas_Event_Flags
+_pinch_rotate_cb(void *data, void *event_info)
+{
+   Widget_Data *wd = data;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
+
+   if (!wd->paused)
+     {
+        int x, y, w, h;
+        Elm_Gesture_Rotate_Info *ei = event_info;
+        evas_object_geometry_get(wd->obj, &x, &y, &w, &h);
 
-   wd->pinch.diff += 0.001;
+        wd->rotate.d = wd->rotate.a + ((ei->base_angle-ei->angle) * 50);
+        wd->rotate.cx = x + ((double)w * 0.5);
+        wd->rotate.cy = y + ((double)h * 0.5);
 
+        evas_object_smart_changed(wd->pan_smart);
+     }
    return EVAS_EVENT_FLAG_NONE;
 }
 
 static Evas_Event_Flags
-zoom_end_cb(void *data, void *event_info __UNUSED__)
+_pinch_rotate_end_cb(void *data, void *event_info __UNUSED__)
 {
    Widget_Data *wd = data;
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
 
-   // FIXME: scroller can be jumping strangely when resizing & scrolling at the sametime (els_scr bug?)
-   elm_smart_scroller_hold_set(wd->scr, 0);
-   elm_smart_scroller_freeze_set(wd->scr, 0);
-   _scr_drag_stop(wd->obj, NULL, NULL);
+   wd->rotate.a = wd->rotate.d;
+
+   return EVAS_EVENT_FLAG_NONE;
+}
+
+static void
+_zoom_mode_set(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Delayed_Data *dd = data;
+
+   dd->wd->mode = dd->mode;
+   if (dd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
+     {
+        Evas_Coord w, h;
+        Evas_Coord vw, vh;
+
+        double zoom;
+        double diff;
+
+        w = dd->wd->size.w;
+        h = dd->wd->size.h;
+        zoom = dd->wd->zoom_detail;
+        _viewport_size_get(dd->wd, &vw, &vh);
 
-   wd->pinch.diff = wd->pinch.level;
+        if (dd->mode == ELM_MAP_ZOOM_MODE_AUTO_FIT)
+          {
+             if ((w < vw) && (h < vh))
+               {
+                  diff = 0.01;
+                  while ((w < vw) && (h < vh))
+                  {
+                     zoom += diff;
+                     w = pow(2.0, zoom) * dd->wd->tsize;
+                     h = pow(2.0, zoom) * dd->wd->tsize;
+                  }
+               }
+             else
+               {
+                  diff = -0.01;
+                  while ((w > vw) || (h > vh))
+                  {
+                     zoom += diff;
+                     w = pow(2.0, zoom) * dd->wd->tsize;
+                     h = pow(2.0, zoom) * dd->wd->tsize;
+                  }
+               }
+
+          }
+        else if (dd->mode == ELM_MAP_ZOOM_MODE_AUTO_FILL)
+          {
+             if ((w < vw) || (h < vh))
+               {
+                  diff = 0.01;
+                  while ((w < vw) || (h < vh))
+                  {
+                     zoom += diff;
+                     w = pow(2.0, zoom) * dd->wd->tsize;
+                     h = pow(2.0, zoom) * dd->wd->tsize;
+                  }
+               }
+             else
+               {
+                  diff = -0.01;
+                  while ((w > vw) && (h > vh))
+                  {
+                     zoom += diff;
+                     w = pow(2.0, zoom) * dd->wd->tsize;
+                     h = pow(2.0, zoom) * dd->wd->tsize;
+                  }
+               }
+          }
+       zoom_with_animation(dd->wd, zoom, 10);
+     }
+}
+
+static void
+_zoom_set(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Delayed_Data *dd = data;
+
+   if (dd->wd->paused) zoom_do(dd->wd, dd->zoom);
+   else zoom_with_animation(dd->wd, dd->zoom, 10);
+   evas_object_smart_changed(dd->wd->pan_smart);
+}
+
+static void
+_region_bring_in(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Delayed_Data *dd = data;
+   int x, y, w, h;
+
+   elm_map_utils_convert_geo_into_coord(dd->wd->obj, dd->lon, dd->lat,
+                                        dd->wd->size.w, &x, &y);
+   _viewport_size_get(dd->wd, &w, &h);
+   x = x - (w / 2);
+   y = y - (h / 2);
+   elm_smart_scroller_region_bring_in(dd->wd->scr, x, y, w, h);
+   evas_object_smart_changed(dd->wd->pan_smart);
+}
+
+static void
+_region_show(void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Delayed_Data *dd = data;
+   int x, y, w, h;
 
-   return EVAS_EVENT_FLAG_NONE;
+   elm_map_utils_convert_geo_into_coord(dd->wd->obj, dd->lon, dd->lat,
+                                        dd->wd->size.w, &x, &y);
+   _viewport_size_get(dd->wd, &w, &h);
+   x = x - (w / 2);
+   y = y - (h / 2);
+   elm_smart_scroller_child_region_show(dd->wd->scr, x, y, w, h);
+   evas_object_smart_changed(dd->wd->pan_smart);
 }
 
-static Evas_Event_Flags
-zoom_cb(void *data, void *event_info)
+static void
+_marker_list_show(void *data)
 {
-   Widget_Data *wd = data;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   Delayed_Data *dd = data;
+   int zoom;
+   double max_lon = -180, min_lon = 180;
+   double max_lat = -90, min_lat = 90;
+   Evas_Coord vw, vh;
+   Elm_Map_Marker *marker;
 
-   if (!wd->paused)
+   EINA_LIST_FREE(dd->markers, marker)
      {
-        int zoom_diff = 0;
-        int x, y, w, h;
-        Elm_Gesture_Zoom_Info *ei = event_info;
-        evas_object_geometry_get(wd->obj, &x, &y, &w, &h);
-
-        wd->pinch.level = wd->pinch.diff * ei->zoom;
-        wd->pinch.cx = x + ((double)w * 0.5);
-        wd->pinch.cy = y + ((double)h * 0.5);
-
-        if (wd->pinch.level > 1.999 || wd->pinch.level < 1.001)
-          {
-             if (wd->pinch.level > 1.999)
-               {
-                  zoom_diff = 1;
-                  wd->pinch.diff = wd->pinch.level / 2.0;
-                  wd->pinch.level = wd->pinch.level / 2.0;
-               }
-             else if (wd->pinch.level < 1.001)
-               {
-                  zoom_diff = -1;
-                  wd->pinch.diff = wd->pinch.level * 2.0;
-                  wd->pinch.level = wd->pinch.level * 2.0;
-               }
-             Elm_Map_Zoom_Mode temp;
-             elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_MOVE, NULL, wd);  // ei->zoom is refreshed
-             temp = wd->mode;
-             wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
-             wd->paused = EINA_TRUE;
-             elm_map_zoom_set(wd->obj, wd->zoom + zoom_diff);
-             wd->paused = EINA_FALSE;
-             wd->mode = temp;
-            elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_MOVE, zoom_cb, wd); // ei->zoom is refreshed
-          }
-        else
-          {
-             if (wd->calc_job) ecore_job_del(wd->calc_job);
-             wd->calc_job = ecore_job_add(_calc_job, wd);
-          }
-        evas_object_smart_callback_call(wd->obj, SIG_ZOOM_CHANGE, NULL);
+        if (marker->longitude > max_lon) max_lon = marker->longitude;
+        if (marker->longitude < min_lon) min_lon = marker->longitude;
+        if (marker->latitude > max_lat) max_lat = marker->latitude;
+        if (marker->latitude < min_lat) min_lat = marker->latitude;
      }
+   dd->lon = (max_lon + min_lon) / 2;
+   dd->lat = (max_lat + min_lat) / 2;
 
-   // FIXME: scroller can be jumping strangely when resizing & scrolling at the sametime (els_scr bug?)
-   _scr_scroll(wd->obj, NULL, NULL);
+   zoom = dd->wd->src->zoom_min;
+   _viewport_size_get(dd->wd, &vw, &vh);
+   while (zoom <= dd->wd->src->zoom_max)
+     {
+        Evas_Coord size, max_x, max_y, min_x, min_y;
+        size = pow(2.0, zoom) * dd->wd->tsize;
+        elm_map_utils_convert_geo_into_coord(dd->wd->obj, min_lon, max_lat, size, &min_x, &max_y);
+        elm_map_utils_convert_geo_into_coord(dd->wd->obj, max_lon, min_lat, size, &max_x, &min_y);
+        if ((max_x - min_x) > vw || (max_y - min_y) > vh) break;
+        zoom++;
+     }
+   zoom--;
 
-   return EVAS_EVENT_FLAG_NONE;
+   zoom_do(dd->wd, zoom);
+   _region_show(dd);
+   evas_object_smart_changed(dd->wd->pan_smart);
 }
 
-static Evas_Event_Flags
-rotate_cb(void *data, void *event_info)
+static char *
+_mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
 {
-   Widget_Data *wd = data;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
+   char buf[PATH_MAX];
+   // ((x+y+zoom)%3)+'a' is requesting map images from distributed tile servers (eg., a, b, c)
+   snprintf(buf, sizeof(buf), "http://%c.tile.openstreetmap.org/%d/%d/%d.png",
+            ((x + y + zoom) % 3) + 'a', zoom, x, y);
+   return strdup(buf);
+}
 
-   if (!wd->paused)
-     {
-        int x, y, w, h;
-        Elm_Gesture_Rotate_Info *ei = event_info;
-        evas_object_geometry_get(wd->obj, &x, &y, &w, &h);
+static char *
+_osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
+{
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "http://%c.tah.openstreetmap.org/Tiles/tile/%d/%d/%d.png",
+            ((x + y + zoom) % 3) + 'a', zoom, x, y);
+   return strdup(buf);
+}
 
-        wd->rotate.d = wd->rotate.a + (ei->base_angle-ei->angle)*50;
-        wd->rotate.cx = x + ((double)w * 0.5);
-        wd->rotate.cy = y + ((double)h * 0.5);
+static char *
+_cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
+{
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "http://%c.tile.opencyclemap.org/cycle/%d/%d/%d.png",
+            (( x + y + zoom) % 3) + 'a', zoom, x, y);
+   return strdup(buf);
+}
 
-        if (wd->calc_job) ecore_job_del(wd->calc_job);
-        wd->calc_job = ecore_job_add(_calc_job, wd);
-     }
-   return EVAS_EVENT_FLAG_NONE;
+static char *
+_mapquest_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
+{
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "http://otile%d.mqcdn.com/tiles/1.0.0/osm/%d/%d/%d.png",
+            ((x + y + zoom) % 4) + 1, zoom, x, y);
+   return strdup(buf);
 }
 
-static Evas_Event_Flags
-rotate_end_cb(void *data, void *event_info __UNUSED__)
+static char *
+_mapquest_aerial_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
 {
-   Widget_Data *wd = data;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EVAS_EVENT_FLAG_NONE);
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf), "http://oatile%d.mqcdn.com/naip/%d/%d/%d.png",
+           ((x + y + zoom) % 4) + 1, zoom, x, y);
+   return strdup(buf);
+}
 
-   wd->rotate.a = wd->rotate.d;
+static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
+{
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "%s?flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&v=%s&fast=%d&instructions=1",
+            ROUTE_YOURS_URL, flat, flon, tlat, tlon, type_name, method);
 
-   return EVAS_EVENT_FLAG_NONE;
+   return strdup(buf);
 }
 
-static void
-_region_get(Widget_Data *wd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *w, Evas_Coord *h)
+// TODO: fix monav api
+/*
+static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
 {
-   EINA_SAFETY_ON_NULL_RETURN(wd);
-   Evas_Coord sx, sy, tx, ty, tcx, tcy, sw, sh, tw, th, rw, rh;
-
-   elm_smart_scroller_child_pos_get(wd->scr, &sx, &sy);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &sw, &sh);
-   rw = wd->size.w * wd->pinch.level;
-   rh = wd->size.h * wd->pinch.level;
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
+            ROUTE_MONAV_URL, flat, flon, tlat, tlon, type_name, method);
 
-   if (wd->size.w < sw)
-     {
-        tw = rw;
-        tcx = sx + tw/2;
-        tx = sx + (sw - tw)/2;
-     }
-   else
-     {
-        tw = sw;
-        tcx = (sx + tw/2) * wd->pinch.level;
-        tx = tcx - tw/2;
+   return strdup(buf);
+}
+*/
 
-     }
-   if (wd->size.h < sh)
-     {
-        th = rh;
-        ty = sy + (sh - th)/2;
-        tcy = sy + th/2;
-     }
-   else
-     {
-        th = sw;
-        tcy = (sy + th/2) * wd->pinch.level;
-        ty = tcy - th/2;
-     }
+// TODO: fix ors api
+/*
+static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
+{
+   char buf[PATH_MAX];
+   snprintf(buf, sizeof(buf),
+            "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
+            ROUTE_ORS_URL, flat, flon, tlat, tlon, type_name, method);
 
-   if (x) *x = tx;
-   if (y) *y = ty;
-   if (cx) *cx= tcx;
-   if (cy) *cy = tcy;
-   if (w) *w = tw;
-   if (h) *h = th;
+   return strdup(buf);
 }
+*/
 
-static void
-_coord_rotate(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)
+static char *
+_nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat)
 {
-   EINA_SAFETY_ON_NULL_RETURN(xx);
-   EINA_SAFETY_ON_NULL_RETURN(yy);
+   ELM_CHECK_WIDTYPE(obj, widtype) strdup("");
+   Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, strdup(""));
 
-   double r = (degree * M_PI) / 180.0;
-   double tx, ty, ttx, tty;
+   char **str;
+   unsigned int ele, idx;
+   char search_url[PATH_MAX];
+   char buf[PATH_MAX];
 
-   tx = x - cx;
-   ty = y - cy;
+   if (method == ELM_MAP_NAME_METHOD_SEARCH)
+     {
+        search_url[0] = '\0';
+        str = eina_str_split_full(name, " ", 0, &ele);
+        for (idx = 0; idx < ele; idx++)
+          {
+             eina_strlcat(search_url, str[idx], sizeof(search_url));
+             if (!(idx == (ele-1)))
+                eina_strlcat(search_url, "+", sizeof(search_url));
+          }
+        snprintf(buf, sizeof(buf),
+                 "%s/search?q=%s&format=xml&polygon=0&addressdetails=0",
+                 NAME_NOMINATIM_URL, search_url);
 
-   ttx = tx * cos(r);
-   tty = tx * sin(r);
-   tx = ttx + (ty * cos(r + M_PI_2));
-   ty = tty + (ty * sin(r + M_PI_2));
+        if (str && str[0])
+          {
+             free(str[0]);
+             free(str);
+          }
+     }
+   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, (int)wd->zoom);
+   else strcpy(buf, "");
 
-   *xx = tx + cx;
-   *yy = ty + cy;
+   return strdup(buf);
 }
 
 #endif
@@ -3038,68 +2869,55 @@ elm_map_add(Evas_Object *parent)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    Evas *e;
    Widget_Data *wd;
-   Evas_Coord minw, minh;
    Evas_Object *obj;
-   static Evas_Smart *smart = NULL;
-   Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
+   Evas_Coord minw, minh;
 
    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
-
    ELM_SET_WIDTYPE(widtype, "map");
    elm_widget_type_set(obj, "map");
    elm_widget_sub_object_add(parent, obj);
-   elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
    elm_widget_data_set(obj, wd);
+   elm_widget_can_focus_set(obj, EINA_TRUE);
+   elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
    elm_widget_del_hook_set(obj, _del_hook);
    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
    elm_widget_theme_hook_set(obj, _theme_hook);
-   elm_widget_can_focus_set(obj, EINA_TRUE);
    elm_widget_event_hook_set(obj, _event_hook);
+   evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, wd);
+   evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, wd);
+   evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, wd);
+   evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, wd);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+                                  _mouse_down, wd);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
+                                  _mouse_up, wd);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
+                                  _mouse_wheel_cb,wd);
+   wd->obj = obj;
 
    wd->scr = elm_smart_scroller_add(e);
+   elm_widget_sub_object_add(obj, wd->scr);
    elm_smart_scroller_widget_set(wd->scr, obj);
    elm_smart_scroller_object_theme_set(obj, wd->scr, "map", "base", "default");
-   evas_object_smart_callback_add(wd->scr, "scroll", _scr, obj);
-   evas_object_smart_callback_add(wd->scr, "drag", _scr, obj);
    elm_widget_resize_object_set(obj, wd->scr);
    elm_smart_scroller_wheel_disabled_set(wd->scr, EINA_TRUE);
-
-   evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
-   evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
-   evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
-   evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
-   evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
-
-   elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
-
-   wd->zoom_min = 0xFF;
-   wd->zoom_max = 0X00;
-   source_init(obj);
-
-   wd->obj = obj;
-   wd->map = evas_map_new(4);
-   if (!wd->map) return NULL;
-
-   wd->markers_max_num = 30;
-   wd->pinch.level = 1.0;
-   wd->pinch.diff = 1.0;
-   wd->markers = calloc(wd->zoom_max + 1, sizeof(void*));
-
-   evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
-   evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
-   evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
-   evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
+   elm_smart_scroller_bounce_allow_set(wd->scr,
+                                       _elm_config->thumbscroll_bounce_enable,
+                                       _elm_config->thumbscroll_bounce_enable);
+   evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                  _changed_size_hints, wd);
+   evas_object_smart_callback_add(wd->scr, "scroll", _scr, wd);
+   evas_object_smart_callback_add(wd->scr, "drag", _scr, wd);
+   evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, wd);
+   evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, wd);
 
    if (!smart)
      {
-        static Evas_Smart_Class sc;
-
-        evas_object_smart_clipped_smart_set(&_pan_sc);
-        sc = _pan_sc;
+        evas_object_smart_clipped_smart_set(&parent_sc);
+        sc = parent_sc;
         sc.name = "elm_map_pan";
         sc.version = EVAS_SMART_CLASS_VERSION;
         sc.add = _pan_add;
-        sc.del = _pan_del;
         sc.resize = _pan_resize;
         sc.move = _pan_move;
         sc.calculate = _pan_calculate;
@@ -3107,75 +2925,58 @@ elm_map_add(Evas_Object *parent)
      }
    if (smart)
      {
+        Pan *pan;
         wd->pan_smart = evas_object_smart_add(e, smart);
-        wd->pan = evas_object_smart_data_get(wd->pan_smart);
-        wd->pan->wd = wd;
+        pan = evas_object_smart_data_get(wd->pan_smart);
+        pan->wd = wd;
      }
+   elm_widget_sub_object_add(obj, wd->pan_smart);
 
    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
                                      _pan_set, _pan_get, _pan_max_get,
                                      _pan_min_get, _pan_child_size_get);
-
-   wd->rect = evas_object_rectangle_add(e);
-   evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_RESIZE,
-                                  _rect_resize_cb, obj);
-   evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_DOWN,
-                                  _mouse_down, obj);
-   evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_UP,
-                                  _mouse_up, obj);
-   evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL,
-                                  _mouse_wheel_cb, obj);
-
-   evas_object_smart_member_add(wd->rect, wd->pan_smart);
-   elm_widget_sub_object_add(obj, wd->rect);
-   evas_object_show(wd->rect);
-   evas_object_color_set(wd->rect, 0, 0, 0, 0);
+   edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
+                             &minw, &minh);
+   evas_object_size_hint_min_set(obj, minw, minh);
 
    wd->ges = elm_gesture_layer_add(obj);
    if (!wd->ges) ERR("elm_gesture_layer_add() failed");
-   elm_gesture_layer_attach(wd->ges, wd->rect);
+   elm_gesture_layer_attach(wd->ges, obj);
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_START,
-                            zoom_start_cb, wd);
+                            _pinch_zoom_start_cb, wd);
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_MOVE,
-                            zoom_cb, wd);
-   elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_END,
-                            zoom_end_cb, wd);
-   elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ZOOM, ELM_GESTURE_STATE_ABORT,
-                            zoom_end_cb, wd);
+                            _pinch_zoom_cb, wd);
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ROTATE, ELM_GESTURE_STATE_MOVE,
-                            rotate_cb, wd);
+                            _pinch_rotate_cb, wd);
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ROTATE, ELM_GESTURE_STATE_END,
-                            rotate_end_cb, wd);
+                            _pinch_rotate_end_cb, wd);
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ROTATE, ELM_GESTURE_STATE_ABORT,
-                            rotate_end_cb, wd);
-
-   wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
-   wd->id = ((int)getpid() << 16) | idnum;
-   idnum++;
-
-   wd->tsize = 256;
-   edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
-                             &minw, &minh);
-   evas_object_size_hint_min_set(obj, minw, minh);
+                            _pinch_rotate_end_cb, wd);
 
    wd->sep_maps_markers = evas_object_rectangle_add(evas_object_evas_get(obj));
+   elm_widget_sub_object_add(obj, wd->sep_maps_markers);
    evas_object_smart_member_add(wd->sep_maps_markers, wd->pan_smart);
 
-   grid_create_all(obj);
+   wd->map = evas_map_new(EVAS_MAP_POINT);
+
+   source_init(wd);
+   wd->tsize = DEFAULT_TILE_SIZE; // FIXME: It should be hard-coded ? or can get from provider?
+
+   wd->id = ((int)getpid() << 16) | idnum;
+   idnum++;
+   _grid_all_create(wd);
 
-   wd->paused = EINA_TRUE;
-   elm_map_zoom_set(obj, 0);
-   wd->paused = EINA_FALSE;
-   _sizing_eval(obj);
+   zoom_do(wd, 0);
+
+   wd->mode = ELM_MAP_ZOOM_MODE_MANUAL;
+   wd->markers_max_num = MARER_MAX_NUMBER;
 
    // TODO: convert Elementary to subclassing of Evas_Smart_Class
    // TODO: and save some bytes, making descriptions per-class and not instance!
    evas_object_smart_callbacks_descriptions_set(obj, _signals);
 
    if (!ecore_file_download_protocol_available("http://"))
-     {
-        ERR("Ecore must be built with curl support for the map widget!");
-     }
+      ERR("Ecore must be built with curl support for the map widget!");
 
    return obj;
 #else
@@ -3190,119 +2991,21 @@ elm_map_zoom_set(Evas_Object *obj, int zoom)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
-   Eina_List *l;
-   Evas_Coord rx, ry, rw, rh;
-   Evas_Object *p;
-   Elm_Map_Route *r;
-   Evas_Object *route;
-   int z = 0;
-
    EINA_SAFETY_ON_NULL_RETURN(wd);
    EINA_SAFETY_ON_NULL_RETURN(wd->src);
-   if (wd->zoom_animator) return;
 
+   if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL) return;
    if (zoom < 0) zoom = 0;
+   if (wd->zoom == zoom) return;
    if (zoom > wd->src->zoom_max) zoom = wd->src->zoom_max;
    if (zoom < wd->src->zoom_min) zoom = wd->src->zoom_min;
 
-   if ((wd->zoom - zoom) > 0) wd->zoom_method = ZOOM_METHOD_OUT;
-   else if ((wd->zoom - zoom) < 0) wd->zoom_method = ZOOM_METHOD_IN;
-   else wd->zoom_method = ZOOM_METHOD_NONE;
-
-   wd->zoom = zoom;
-   wd->size.ow = wd->size.w;
-   wd->size.oh = wd->size.h;
-   elm_smart_scroller_child_pos_get(wd->scr, &rx, &ry);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
-
-   EINA_LIST_FOREACH(wd->route, l, r)
-     {
-        if (r)
-          {
-             EINA_LIST_FOREACH(r->path, l, p)
-               {
-                  evas_object_polygon_points_clear(p);
-               }
-          }
-     }
-
-   EINA_LIST_FOREACH(wd->track, l, route)
-     {
-       evas_object_hide(route);
-     }
-
-   if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
-     {
-        int p2w, p2h;
-        int cumulw, cumulh;
-
-        cumulw = wd->tsize;
-        p2w = 0;
-        while (cumulw <= rw)
-          {
-             p2w++;
-             cumulw *= 2;
-          }
-        p2w--;
-
-        cumulh = wd->tsize;
-        p2h = 0;
-        while (cumulh <= rh)
-          {
-             p2h++;
-             cumulh *= 2;
-          }
-        p2h--;
-
-        if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FIT)
-          {
-             if (p2w < p2h) z = p2w;
-             else z = p2h;
-          }
-        else if (wd->mode == ELM_MAP_ZOOM_MODE_AUTO_FILL)
-          {
-             if (p2w > p2h) z = p2w;
-             else z = p2h;
-          }
-        wd->zoom = z;
-     }
-
-   wd->size.nw = pow(2.0, wd->zoom) * wd->tsize;
-   wd->size.nh = pow(2.0, wd->zoom) * wd->tsize;
-   wd->t = 1.0;
-
-   if ((wd->size.w > 0) && (wd->size.h > 0))
-     {
-        wd->size.spos.x = (double)(rx + (rw / 2)) / (double)wd->size.ow;
-        wd->size.spos.y = (double)(ry + (rh / 2)) / (double)wd->size.oh;
-     }
-   else
-     {
-        wd->size.spos.x = 0.5;
-        wd->size.spos.y = 0.5;
-     }
-
-   if (rw > wd->size.ow) wd->size.spos.x = 0.5;
-   if (rh > wd->size.oh) wd->size.spos.y = 0.5;
-   if (wd->size.spos.x > 1.0) wd->size.spos.x = 1.0;
-   if (wd->size.spos.y > 1.0) wd->size.spos.y = 1.0;
-
-   if (wd->paused)
-     {
-        zoom_do(obj);
-     }
-   else
-     {
-        if (!wd->zoom_animator)
-          {
-             wd->zoom_animator = ecore_animator_add(_zoom_anim, obj);
-             wd->nosmooth++;
-             if (wd->nosmooth == 1) _smooth_update(obj);
-             evas_object_smart_callback_call(obj, SIG_ZOOM_START, NULL);
-          }
-     }
-
-   if (wd->zoom_method != ZOOM_METHOD_NONE) evas_object_smart_callback_call(obj, SIG_ZOOM_CHANGE, NULL);
+   Delayed_Data *data = ELM_NEW(Delayed_Data);
+   data->func = _zoom_set;
+   data->wd = wd;
+   data->zoom = zoom;
+   data->wd->delayed_jobs = eina_list_append(data->wd->delayed_jobs, data);
+   evas_object_smart_changed(data->wd->pan_smart);
 #else
    (void) obj;
    (void) zoom;
@@ -3316,7 +3019,7 @@ elm_map_zoom_get(const Evas_Object *obj)
    ELM_CHECK_WIDTYPE(obj, widtype) 0;
    Widget_Data *wd = elm_widget_data_get(obj);
 
-   if (!wd) return 0;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, 0);
    return wd->zoom;
 #else
    (void) obj;
@@ -3330,17 +3033,14 @@ elm_map_zoom_mode_set(Evas_Object *obj, Elm_Map_Zoom_Mode mode)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
-   if (wd->mode == mode) return;
-   wd->mode = mode;
-
-   if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL)
-     {
-        int tz = wd->zoom;
-        wd->zoom = 0;
-        elm_map_zoom_set(wd->obj, tz);
-     }
+   Delayed_Data *data = ELM_NEW(Delayed_Data);
+   data->mode = mode;
+   data->func = _zoom_mode_set;
+   data->wd = wd;
+   data->wd->delayed_jobs = eina_list_append(data->wd->delayed_jobs, data);
+   evas_object_smart_changed(data->wd->pan_smart);
 #else
    (void) obj;
    (void) mode;
@@ -3353,8 +3053,8 @@ elm_map_zoom_mode_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_ZOOM_MODE_MANUAL;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, ELM_MAP_ZOOM_MODE_MANUAL);
 
-   if (!wd) return ELM_MAP_ZOOM_MODE_MANUAL;
    return wd->mode;
 #else
    (void) obj;
@@ -3368,29 +3068,14 @@ elm_map_geo_region_bring_in(Evas_Object *obj, double lon, double lat)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
-   int rx, ry, rw, rh;
 
-   if (!wd) return;
-   elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
-
-   rx = rx - rw / 2;
-   ry = ry - rh / 2;
-
-   if (wd->zoom_animator)
-     {
-        wd->nosmooth--;
-        if (!wd->nosmooth) _smooth_update(obj);
-        ecore_animator_del(wd->zoom_animator);
-        wd->zoom_animator = NULL;
-        zoom_do(obj);
-        evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
-     }
-   elm_smart_scroller_region_bring_in(wd->scr, rx, ry, rw, rh);
-
-   wd->center_on.enabled = EINA_TRUE;
-   wd->center_on.lon = lon;
-   wd->center_on.lat = lat;
+   Delayed_Data *data = ELM_NEW(Delayed_Data);
+   data->func = _region_bring_in;
+   data->wd = wd;
+   data->lon = lon;
+   data->lat = lat;
+   data->wd->delayed_jobs = eina_list_append(data->wd->delayed_jobs, data);
+   evas_object_smart_changed(data->wd->pan_smart);
 #else
    (void) obj;
    (void) lon;
@@ -3400,32 +3085,18 @@ elm_map_geo_region_bring_in(Evas_Object *obj, double lon, double lat)
 
 EAPI void
 elm_map_geo_region_show(Evas_Object *obj, double lon, double lat)
-{
-#ifdef HAVE_ELEMENTARY_ECORE_CON
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   int rx, ry, rw, rh;
-
-   if (!wd) return;
-   elm_map_utils_convert_geo_into_coord(obj, lon, lat, wd->size.w, &rx, &ry);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
-
-   rx = rx - rw / 2;
-   ry = ry - rh / 2;
-
-   if (wd->zoom_animator)
-     {
-        wd->nosmooth--;
-        ecore_animator_del(wd->zoom_animator);
-        wd->zoom_animator = NULL;
-        zoom_do(obj);
-        evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
-     }
-   elm_smart_scroller_child_region_show(wd->scr, rx, ry, rw, rh);
+{
+#ifdef HAVE_ELEMENTARY_ECORE_CON
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
 
-   wd->center_on.enabled = EINA_TRUE;
-   wd->center_on.lon = lon;
-   wd->center_on.lat = lat;
+   Delayed_Data *data = ELM_NEW(Delayed_Data);
+   data->func = _region_show;
+   data->wd = wd;
+   data->lon = lon;
+   data->lat = lat;
+   data->wd->delayed_jobs = eina_list_append(data->wd->delayed_jobs, data);
+   evas_object_smart_changed(data->wd->pan_smart);
 #else
    (void) obj;
    (void) lon;
@@ -3439,14 +3110,15 @@ elm_map_geo_region_get(const Evas_Object *obj, double *lon, double *lat)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord cx, cy;
-   int rw;
-   double tlon, tlat;
    EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   _region_get(wd, NULL, NULL, &cx, &cy, NULL, NULL);
-   rw = wd->size.w * wd->pinch.level;
-   elm_map_utils_convert_coord_into_geo(obj, cx, cy, rw, &tlon, &tlat);
+   double tlon, tlat;
+   Evas_Coord px, py, vw, vh;
+
+   _pan_geometry_get(wd, &px, &py);
+   _viewport_size_get(wd, &vw, &vh);
+   elm_map_utils_convert_coord_into_geo(obj, vw/2 - px, vh/2 -py, wd->size.w,
+                                        &tlon, &tlat);
    if (lon) *lon = tlon;
    if (lat) *lat = tlat;
 #else
@@ -3462,8 +3134,8 @@ elm_map_paused_set(Evas_Object *obj, Eina_Bool paused)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    if (wd->paused == !!paused) return;
    wd->paused = !!paused;
    if (wd->paused)
@@ -3472,8 +3144,7 @@ elm_map_paused_set(Evas_Object *obj, Eina_Bool paused)
           {
              if (wd->zoom_animator) ecore_animator_del(wd->zoom_animator);
              wd->zoom_animator = NULL;
-             zoom_do(obj);
-             evas_object_smart_callback_call(obj, SIG_ZOOM_STOP, NULL);
+             zoom_do(wd, wd->zoom);
           }
         edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
                                 "elm,state,busy,stop", "elm");
@@ -3496,8 +3167,8 @@ elm_map_paused_markers_set(Evas_Object *obj, Eina_Bool paused)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    if (wd->paused_markers == !!paused) return;
    wd->paused_markers = paused;
 #else
@@ -3512,8 +3183,8 @@ elm_map_paused_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
 
-   if (!wd) return EINA_FALSE;
    return wd->paused;
 #else
    (void) obj;
@@ -3527,8 +3198,8 @@ elm_map_paused_markers_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
 
-   if (!wd) return EINA_FALSE;
    return wd->paused_markers;
 #else
    (void) obj;
@@ -3542,17 +3213,10 @@ elm_map_utils_downloading_status_get(const Evas_Object *obj, int *try_num, int *
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
-   if (try_num)
-     {
-        *try_num = wd->try_num;
-     }
-
-   if (finish_num)
-     {
-        *finish_num = wd->finish_num;
-     }
+   if (try_num) *try_num = wd->try_num;
+   if (finish_num) *finish_num = wd->finish_num;
 #else
    (void) obj;
    (void) try_num;
@@ -3566,21 +3230,18 @@ elm_map_utils_convert_coord_into_geo(const Evas_Object *obj, int x, int y, int s
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    int zoom = floor(log(size / 256) / log(2));
    if ((wd->src) && (wd->src->coord_into_geo))
      {
         if (wd->src->coord_into_geo(obj, zoom, x, y, size, lon, lat)) return;
      }
 
-   if (lon)
-     {
-        *lon = x / (double)size * 360.0 - 180;
-     }
+   if (lon) *lon = (x / (double)size * 360.0) - 180;
    if (lat)
      {
-        double n = ELM_PI - 2.0 * ELM_PI * y / size;
+        double n = ELM_PI - (2.0 * ELM_PI * y / size);
         *lat = 180.0 / ELM_PI * atan(0.5 * (exp(n) - exp(-n)));
      }
 #else
@@ -3599,18 +3260,18 @@ elm_map_utils_convert_geo_into_coord(const Evas_Object *obj, double lon, double
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    int zoom = floor(log(size / 256) / log(2));
    if ((wd->src) && (wd->src->geo_into_coord))
      {
         if (wd->src->geo_into_coord(obj, zoom, lon, lat, size, x, y)) return;
      }
 
-   if (x)
-     *x = floor((lon + 180.0) / 360.0 * size);
+   if (x) *x = floor((lon + 180.0) / 360.0 * size);
    if (y)
-     *y = floor((1.0 - log( tan(lat * ELM_PI / 180.0) + 1.0 / cos(lat * ELM_PI / 180.0)) / ELM_PI) / 2.0 * size);
+      *y = floor((1.0 - log(tan(lat * ELM_PI / 180.0) + (1.0 / cos(lat * ELM_PI / 180.0)))
+                 / ELM_PI) / 2.0 * size);
 #else
    (void) obj;
    (void) lon;
@@ -3667,7 +3328,7 @@ elm_map_utils_rotate_coord(const Evas_Object *obj, const Evas_Coord x, const Eva
 }
 
 EAPI void
-elm_map_canvas_to_geo_convert(const Evas_Object *obj, const Evas_Coord x, const Evas_Coord y, double *lon, double *lat)
+elm_map_canvas_to_geo_convert(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, double *lon, double *lat)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
@@ -3676,25 +3337,12 @@ elm_map_canvas_to_geo_convert(const Evas_Object *obj, const Evas_Coord x, const
    EINA_SAFETY_ON_NULL_RETURN(lat);
    EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   Evas_Coord xx, yy, w, h, mw, tx, ty, cx, cy;
-   double d;
-
-   _region_get(wd, &xx, &yy, &cx, &cy, &w, &h);
-   mw = wd->size.w * wd->pinch.level;
-   if (w < mw)
-     {
-        xx += x;
-        yy += y;
-     }
-   else
-     {
-        xx = x - xx;
-        yy = y - yy;
-     }
-
-   elm_map_rotate_get(obj, &d, NULL, NULL);
-   _coord_rotate(xx, yy, cx, cy, -d, &tx, &ty);
-   elm_map_utils_convert_coord_into_geo(obj, tx, ty, mw, lon, lat);
+   Evas_Coord px, py, vw, vh;
+   _pan_geometry_get(wd, &px, &py);
+   _viewport_size_get(wd, &vw, &vh);
+   _coord_rotate(x - px, y - py, (vw / 2) - px, (vh / 2) - py, -wd->rotate.d,
+                 &x, &y);
+   elm_map_utils_convert_coord_into_geo(obj, x, y, wd->size.w, lon, lat);
 #else
    (void) obj;
    (void) x;
@@ -3705,196 +3353,48 @@ elm_map_canvas_to_geo_convert(const Evas_Object *obj, const Evas_Coord x, const
 }
 
 EAPI Elm_Map_Marker *
-elm_map_marker_add(Evas_Object *obj, double lon, double lat, Elm_Map_Marker_Class *clas, Elm_Map_Group_Class *clas_group, void *data)
+elm_map_marker_add(Evas_Object *obj, double lon, double lat, Elm_Map_Marker_Class *clas, Elm_Map_Group_Class *group_clas, void *data)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
-   int i, j;
-   Eina_List *l;
-   Marker_Group *group;
-   int mpi, mpj;
-   int tabi[9];
-   int tabj[9];
-   const char *s;
-   const char *style;
-   Evas_Object *o;
 
-   if (!wd) return NULL;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(clas_group, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
    EINA_SAFETY_ON_NULL_RETURN_VAL(clas, NULL);
 
    Elm_Map_Marker *marker = ELM_NEW(Elm_Map_Marker);
-
    marker->wd = wd;
    marker->clas = clas;
-   marker->clas_group = clas_group;
+   marker->group_clas = group_clas;
    marker->longitude = lon;
    marker->latitude = lat;
    marker->data = data;
-   marker->x = calloc(wd->zoom_max + 1, sizeof(Evas_Coord));
-   marker->y = calloc(wd->zoom_max + 1, sizeof(Evas_Coord));
-   marker->groups = calloc(wd->zoom_max + 1, sizeof(Marker_Group*));
-
-   tabi[1] = tabi[4] = tabi[6] = -1;
-   tabi[2] = tabi[0] = tabi[7] = 0;
-   tabi[3] = tabi[5] = tabi[8] = 1;
-
-   tabj[1] = tabj[2] = tabj[3] = -1;
-   tabj[4] = tabj[0] = tabj[5] = 0;
-   tabj[6] = tabj[7] = tabj[8] = 1;
-
-   if (!clas_group->priv.set)
-     {
-        style = "radio";
-        if (marker->clas_group && marker->clas_group->style)
-          style = marker->clas_group->style;
-
-        o = edje_object_add(evas_object_evas_get(obj));
-        _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
-        s = edje_object_data_get(o, "size_w");
-        if (s) clas_group->priv.edje_w = atoi(s);
-        else clas_group->priv.edje_w = 0;
-        s = edje_object_data_get(o, "size_h");
-        if (s) clas_group->priv.edje_h = atoi(s);
-        else clas_group->priv.edje_h = 0;
-        s = edje_object_data_get(o, "size_max_w");
-        if (s) clas_group->priv.edje_max_w = atoi(s);
-        else clas_group->priv.edje_max_w = 0;
-        s = edje_object_data_get(o, "size_max_h");
-        if (s) clas_group->priv.edje_max_h = atoi(s);
-        else clas_group->priv.edje_max_h = 0;
-        evas_object_del(o);
-
-        clas_group->priv.set = EINA_TRUE;
-     }
-
-   if (!clas->priv.set)
-     {
-        style = "radio";
-        if (marker->clas && marker->clas->style)
-          style = marker->clas->style;
-
-        o = edje_object_add(evas_object_evas_get(obj));
-        _elm_theme_object_set(obj, o, "map/marker", style, elm_widget_style_get(obj));
-        s = edje_object_data_get(o, "size_w");
-        if (s) clas->priv.edje_w = atoi(s);
-        else clas->priv.edje_w = 0;
-        s = edje_object_data_get(o, "size_h");
-        if (s) clas->priv.edje_h = atoi(s);
-        else clas->priv.edje_h = 0;
-        evas_object_del(o);
-
-        clas->priv.set = EINA_TRUE;
-     }
-
-   for (i = clas_group->zoom_displayed; i <= wd->zoom_max; i++)
-     {
-        elm_map_utils_convert_geo_into_coord(obj, lon, lat, pow(2.0, i)*wd->tsize,
-                                             &(marker->x[i]), &(marker->y[i]));
-
-        //search in the matrixsparse the region where the marker will be
-        mpi = marker->x[i] / wd->tsize;
-        mpj = marker->y[i] / wd->tsize;
-
-        if (!wd->markers[i])
-          {
-             int size =  pow(2.0, i);
-             wd->markers[i] = eina_matrixsparse_new(size, size, NULL, NULL);
-          }
-
-        group = NULL;
-        if (i <= clas_group->zoom_grouped)
-          {
-             for (j = 0, group = NULL; j < 9 && !group; j++)
-               {
-                  EINA_LIST_FOREACH(eina_matrixsparse_data_idx_get(wd->markers[i], mpj + tabj[j], mpi + tabi[j]),
-                                    l, group)
-                    {
-                       if (group->clas == marker->clas_group
-                           && ELM_RECTS_INTERSECT(marker->x[i]-clas->priv.edje_w/4,
-                                                  marker->y[i]-clas->priv.edje_h/4, clas->priv.edje_w, clas->priv.edje_h,
-                                                  group->x-group->w/4, group->y-group->h/4, group->w, group->h))
-                         {
-                            group->markers = eina_list_append(group->markers, marker);
-                            group->update_nbelems = EINA_TRUE;
-                            group->update_resize = EINA_TRUE;
-
-                            group->sum_x += marker->x[i];
-                            group->sum_y += marker->y[i];
-                            group->x = group->sum_x / eina_list_count(group->markers);
-                            group->y = group->sum_y / eina_list_count(group->markers);
-
-                            group->w = group->clas->priv.edje_w + group->clas->priv.edje_w/8.
-                               * eina_list_count(group->markers);
-                            group->h = group->clas->priv.edje_h + group->clas->priv.edje_h/8.
-                               * eina_list_count(group->markers);
-                            if (group->w > group->clas->priv.edje_max_w) group->w = group->clas->priv.edje_max_w;
-                            if (group->h > group->clas->priv.edje_max_h) group->h = group->clas->priv.edje_max_h;
-
-                            if (group->obj && eina_list_count(group->markers) == 2)
-                              {
-                                 _group_object_free(group);
-                                 _group_object_create(group);
-                              }
-                            if (group->bubble)
-                              _group_bubble_content_update(group);
-
-                            break;
-                         }
-                    }
-               }
-          }
-        if (!group)
-          {
-             group = calloc(1, sizeof(Marker_Group));
-             group->wd = wd;
-             group->sum_x = marker->x[i];
-             group->sum_y = marker->y[i];
-             group->x = marker->x[i];
-             group->y = marker->y[i];
-             group->w = clas_group->priv.edje_w;
-             group->h = clas_group->priv.edje_h;
-             group->clas = clas_group;
-
-             group->markers = eina_list_append(group->markers, marker);
-             group->update_nbelems = EINA_TRUE;
-             group->update_resize = EINA_TRUE;
-
-             eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
-
-             if (!group->cell)
-               {
-                  l = eina_list_append(NULL, group);
-                  eina_matrixsparse_data_idx_set(wd->markers[i], mpj, mpi, l);
-                  eina_matrixsparse_cell_idx_get(wd->markers[i], mpj, mpi, &(group->cell));
-               }
-             else
-               {
-                  l = eina_matrixsparse_cell_data_get(group->cell);
-                  l = eina_list_append(l, group);
-                  eina_matrixsparse_cell_data_set(group->cell, l);
-               }
-          }
-        marker->groups[i] = group;
-     }
-
-   if (wd->grids)
-     {
-        Grid *g;
-        Evas_Coord ox, oy, ow, oh;
-        evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
-        g = _get_current_grid(wd);
-        marker_place(obj, g, wd->pan_x, wd->pan_y, ox, oy, ow, oh);
-     }
-
+   marker->x = 0;
+   marker->y = 0;
+   _edj_marker_size_get(wd, &marker->w, &marker->h);
+
+   marker->obj = elm_layout_add(wd->obj);
+   evas_object_smart_member_add(marker->obj, wd->pan_smart);
+   evas_object_stack_above(marker->obj, wd->sep_maps_markers);
+
+   edje_object_signal_callback_add(elm_layout_edje_get(marker->obj),
+                                   "open", "elm", _marker_bubble_open_cb,
+                                   marker);
+   edje_object_signal_callback_add(elm_layout_edje_get(marker->obj),
+                                   "bringin", "elm", _marker_bringin_cb,
+                                   marker);
+
+   wd->markers = eina_list_append(wd->markers, marker);
+   if (marker->group_clas) group_clas->markers = eina_list_append(group_clas->markers,
+                                                                  marker);
+   evas_object_smart_changed(wd->pan_smart);
    return marker;
 #else
    (void) obj;
    (void) lon;
    (void) lat;
    (void) clas;
-   (void) clas_group;
+   (void) group_clas;
    (void) data;
    return NULL;
 #endif
@@ -3904,70 +3404,24 @@ EAPI void
 elm_map_marker_remove(Elm_Map_Marker *marker)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
-   int i;
-   Eina_List *groups;
-   Widget_Data *wd;
-
    EINA_SAFETY_ON_NULL_RETURN(marker);
-   wd = marker->wd;
-   if (!wd) return;
-   for (i = marker->clas_group->zoom_displayed; i <= wd->zoom_max; i++)
-     {
-        marker->groups[i]->markers = eina_list_remove(marker->groups[i]->markers, marker);
-        if (!eina_list_count(marker->groups[i]->markers))
-          {
-             groups = eina_matrixsparse_cell_data_get(marker->groups[i]->cell);
-             groups = eina_list_remove(groups, marker->groups[i]);
-             eina_matrixsparse_cell_data_set(marker->groups[i]->cell, groups);
-
-             _group_object_free(marker->groups[i]);
-             _group_bubble_free(marker->groups[i]);
-             free(marker->groups[i]);
-          }
-        else
-          {
-             marker->groups[i]->sum_x -= marker->x[i];
-             marker->groups[i]->sum_y -= marker->y[i];
-
-             marker->groups[i]->x = marker->groups[i]->sum_x / eina_list_count(marker->groups[i]->markers);
-             marker->groups[i]->y = marker->groups[i]->sum_y / eina_list_count(marker->groups[i]->markers);
-
-             marker->groups[i]->w = marker->groups[i]->clas->priv.edje_w
-                + marker->groups[i]->clas->priv.edje_w/8. * eina_list_count(marker->groups[i]->markers);
-             marker->groups[i]->h = marker->groups[i]->clas->priv.edje_h
-                + marker->groups[i]->clas->priv.edje_h/8. * eina_list_count(marker->groups[i]->markers);
-             if (marker->groups[i]->w > marker->groups[i]->clas->priv.edje_max_w)
-               marker->groups[i]->w = marker->groups[i]->clas->priv.edje_max_w;
-             if (marker->groups[i]->h > marker->groups[i]->clas->priv.edje_max_h)
-               marker->groups[i]->h = marker->groups[i]->clas->priv.edje_max_h;
-
-             if ((marker->groups[i]->obj) && (eina_list_count(marker->groups[i]->markers) == 1))
-               {
-                  _group_object_free(marker->groups[i]);
-                  _group_object_create(marker->groups[i]);
-               }
-          }
-     }
+   Widget_Data *wd = marker->wd;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
    if ((marker->content) && (marker->clas->func.del))
-     marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
-   else if (marker->content)
-     evas_object_del(marker->content);
+      marker->clas->func.del(wd->obj, marker, marker->data, marker->content);
 
-   if (marker->x) free(marker->x);
-   if (marker->y) free(marker->y);
-   if (marker->groups) free(marker->groups);
+   if (marker->bubble) _bubble_free(marker->bubble);
+   if (marker->group) _marker_group_free(marker->group);
 
+   if (marker->group_clas)
+      marker->group_clas->markers = eina_list_remove(marker->group_clas->markers, marker);
+   wd->markers = eina_list_remove(wd->markers, marker);
+
+   evas_object_del(marker->obj);
    free(marker);
 
-   if (wd->grids)
-     {
-        Grid *g;
-        Evas_Coord ox, oy, ow, oh;
-        evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
-        g = _get_current_grid(wd);
-        marker_place(wd->obj, g, wd->pan_x, wd->pan_y, ox, oy, ow, oh);
-     }
+   evas_object_smart_changed(wd->pan_smart);
 #else
    (void) marker;
 #endif
@@ -4013,49 +3467,18 @@ EAPI void
 elm_map_markers_list_show(Eina_List *markers)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
-   int zoom;
-   double lon, lat;
-   Eina_List *l;
-   Elm_Map_Marker *marker, *m_max_lon = NULL, *m_max_lat = NULL, *m_min_lon = NULL, *m_min_lat = NULL;
-   Evas_Coord rw, rh, xc, yc;
-   Widget_Data *wd;
-
    EINA_SAFETY_ON_NULL_RETURN(markers);
-   EINA_LIST_FOREACH(markers, l, marker)
-     {
-        wd = marker->wd;
-
-        if ((!m_min_lon) || (marker->longitude < m_min_lon->longitude))
-          m_min_lon = marker;
-
-        if ((!m_max_lon) || (marker->longitude > m_max_lon->longitude))
-          m_max_lon = marker;
+   EINA_SAFETY_ON_TRUE_RETURN(!eina_list_count(markers));
 
-        if ((!m_min_lat) || (marker->latitude > m_min_lat->latitude))
-          m_min_lat = marker;
-
-        if ((!m_max_lat) || (marker->latitude < m_max_lat->latitude))
-          m_max_lat = marker;
-     }
-
-   lon = (m_max_lon->longitude - m_min_lon->longitude) / 2. + m_min_lon->longitude;
-   lat = (m_max_lat->latitude - m_min_lat->latitude) / 2. + m_min_lat->latitude;
-
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &rw, &rh);
-   for (zoom = wd->src->zoom_max; zoom > wd->src->zoom_min; zoom--)
-     {
-        Evas_Coord size = pow(2.0, zoom)*wd->tsize;
-        elm_map_utils_convert_geo_into_coord(wd->obj, lon, lat, size, &xc, &yc);
-
-        if ((m_min_lon->x[zoom] - wd->marker_max_w >= xc-rw/2)
-            && (m_min_lat->y[zoom] - wd->marker_max_h >= yc-rh/2)
-            && (m_max_lon->x[zoom] + wd->marker_max_w <= xc+rw/2)
-            && (m_max_lat->y[zoom] + wd->marker_max_h <= yc+rh/2))
-          break;
-     }
-
-   elm_map_geo_region_show(wd->obj, lon, lat);
-   elm_map_zoom_set(wd->obj, zoom);
+   Elm_Map_Marker *marker;
+   marker = eina_list_data_get(markers);
+
+   Delayed_Data *data = ELM_NEW(Delayed_Data);
+   data->func = _marker_list_show;
+   data->wd = marker->wd;
+   data->markers = eina_list_clone(markers);
+   data->wd->delayed_jobs = eina_list_append(data->wd->delayed_jobs, data);
+   evas_object_smart_changed(data->wd->pan_smart);
 #else
    (void) markers;
 #endif
@@ -4067,8 +3490,8 @@ elm_map_max_marker_per_group_set(Evas_Object *obj, int max)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    wd->markers_max_num = max;
 #else
    (void) obj;
@@ -4093,15 +3516,10 @@ elm_map_marker_update(Elm_Map_Marker *marker)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    EINA_SAFETY_ON_NULL_RETURN(marker);
-   if (marker->content)
-     {
-        if (marker->clas->func.del)
-          marker->clas->func.del(marker->wd->obj, marker, marker->data, marker->content);
-        else
-          evas_object_del(marker->content);
-        marker->content = NULL;
-        _group_bubble_content_update(marker->groups[marker->wd->zoom]);
-     }
+   Widget_Data *wd = marker->wd;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+
+   _marker_update(marker);
 #else
    (void) marker;
 #endif
@@ -4113,12 +3531,21 @@ elm_map_bubbles_close(Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
-   Marker_Group *group;
-   Eina_List *l, *l_next;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
-   EINA_LIST_FOREACH_SAFE(wd->opened_bubbles, l, l_next, group)
-      _group_bubble_free(group);
+   Eina_List *l;
+   Elm_Map_Marker *marker;
+   EINA_LIST_FOREACH(wd->markers, l, marker)
+     {
+        if (marker->bubble) _bubble_free(marker->bubble);
+        marker->bubble = NULL;
+
+        if (marker->group)
+          {
+             if (marker->group->bubble) _bubble_free(marker->group->bubble);
+             marker->group->bubble = NULL;
+          }
+     }
 #else
    (void) obj;
 #endif
@@ -4130,11 +3557,16 @@ elm_map_group_class_new(Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+
+   Elm_Map_Group_Class *clas = ELM_NEW(Elm_Map_Group_Class);
+   clas->wd = wd;
+   clas->zoom_displayed = 0;
+   clas->zoom_grouped = 255;
+   eina_stringshare_replace(&clas->style, "radio");
+
+   wd->group_classes = eina_list_append(wd->group_classes, clas);
 
-   if (!wd) return NULL;
-   Elm_Map_Group_Class *clas = calloc(1, sizeof(Elm_Map_Group_Class));
-   clas->zoom_grouped = wd->zoom_max;
-   wd->groups_clas = eina_list_append(wd->groups_clas, clas);
    return clas;
 #else
    (void) obj;
@@ -4208,19 +3640,11 @@ elm_map_group_class_hide_set(Evas_Object *obj, Elm_Map_Group_Class *clas, Eina_B
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
    EINA_SAFETY_ON_NULL_RETURN(clas);
-   if (clas->hide == hide) return;
+
    clas->hide = hide;
-   if (wd->grids)
-     {
-        Grid *g;
-        Evas_Coord ox, oy, ow, oh;
-        evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
-        g = _get_current_grid(wd);
-        marker_place(obj, g, wd->pan_x, wd->pan_y, ox, oy, ow, oh);
-     }
+   evas_object_smart_changed(wd->pan_smart);
 #else
    (void) obj;
    (void) clas;
@@ -4234,10 +3658,12 @@ elm_map_marker_class_new(Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
 
-   if (!wd) return NULL;
-   Elm_Map_Marker_Class *clas = calloc(1, sizeof(Elm_Map_Marker_Class));
-   wd->markers_clas = eina_list_append(wd->markers_clas, clas);
+   Elm_Map_Marker_Class *clas = ELM_NEW(Elm_Map_Marker_Class);
+   eina_stringshare_replace(&clas->style, "radio");
+
+   wd->marker_classes = eina_list_append(wd->marker_classes, clas);
    return clas;
 #else
    (void) obj;
@@ -4299,9 +3725,9 @@ elm_map_source_names_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
 
-   if (!wd) return NULL;
-   return wd->source_names;
+   return wd->src_names;
 #else
    (void) obj;
    return NULL;
@@ -4314,19 +3740,20 @@ elm_map_source_name_set(Evas_Object *obj, const char *source_name)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+
    Map_Sources_Tab *s;
    Eina_List *l;
    int zoom;
 
-   if (!wd) return;
    if (wd->src)
      {
         if (!strcmp(wd->src->name, source_name)) return;
         if (!wd->src->url_cb) return;
      }
 
-   grid_clear_all(obj);
-   EINA_LIST_FOREACH(wd->map_sources_tab, l, s)
+   _grid_all_clear(wd);
+   EINA_LIST_FOREACH(wd->srcs, l, s)
      {
         if (!strcmp(s->name, source_name))
           {
@@ -4343,9 +3770,11 @@ elm_map_source_name_set(Evas_Object *obj, const char *source_name)
           zoom = wd->src->zoom_max;
         if (wd->src->zoom_min > zoom)
           zoom = wd->src->zoom_min;
+        if (wd->src->zoom_max < wd->zoom_max) wd->zoom_max = wd->src->zoom_max;
+        if (wd->src->zoom_min > wd->zoom_min) wd->zoom_min = wd->src->zoom_min;
      }
-   grid_create_all(obj);
-   elm_map_zoom_set(obj, zoom);
+   _grid_all_create(wd);
+   zoom_do(wd, zoom);
 #else
    (void) obj;
    (void) source_name;
@@ -4373,8 +3802,8 @@ elm_map_route_source_set(Evas_Object *obj, Elm_Map_Route_Sources source)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    wd->route_source = source;
 #else
    (void) obj;
@@ -4388,8 +3817,8 @@ elm_map_route_source_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) ELM_MAP_ROUTE_SOURCE_YOURS;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, ELM_MAP_ROUTE_SOURCE_YOURS);
 
-   if (!wd) return ELM_MAP_ROUTE_SOURCE_YOURS;
    return wd->route_source;
 #else
    (void) obj;
@@ -4403,10 +3832,11 @@ elm_map_source_zoom_max_set(Evas_Object *obj, int zoom)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN(wd->src);
 
-   if ((!wd) || (!wd->src)) return;
-   if ((zoom > wd->zoom_max) || (zoom < wd->zoom_min)) return;
-   wd->src->zoom_max = zoom;
+   if ((zoom > wd->src->zoom_max) || (zoom < wd->src->zoom_min)) return;
+   wd->zoom_max = zoom;
 #else
    (void) obj;
    (void) zoom;
@@ -4419,9 +3849,10 @@ elm_map_source_zoom_max_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) 18;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src, -1);
 
-   if ((!wd) || (!wd->src)) return 18;
-   return wd->src->zoom_max;
+   return wd->zoom_max;
 #else
    (void) obj;
    return 18;
@@ -4434,10 +3865,11 @@ elm_map_source_zoom_min_set(Evas_Object *obj, int zoom)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN(wd->src);
 
-   if ((!wd) || (!wd->src)) return;
-   if ((zoom > wd->zoom_max) || (zoom < wd->zoom_min)) return;
-   wd->src->zoom_min = zoom;
+   if ((zoom > wd->src->zoom_max) || (zoom < wd->src->zoom_min)) return;
+   wd->zoom_min = zoom;
 #else
    (void) obj;
    (void) zoom;
@@ -4450,9 +3882,10 @@ elm_map_source_zoom_min_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) 0;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src, -1);
 
-   if ((!wd) || (!wd->src)) return 0;
-   return wd->src->zoom_min;
+   return wd->zoom_min;
 #else
    (void) obj;
    return 0;
@@ -4465,10 +3898,10 @@ elm_map_user_agent_set(Evas_Object *obj, const char *user_agent)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
+   EINA_SAFETY_ON_NULL_RETURN(user_agent);
 
-   if (!wd) return;
-   if (!wd->user_agent) wd->user_agent = eina_stringshare_add(user_agent);
-   else eina_stringshare_replace(&wd->user_agent, user_agent);
+   eina_stringshare_replace(&wd->user_agent, user_agent);
 
    if (!wd->ua) wd->ua = eina_hash_string_small_new(NULL);
    eina_hash_set(wd->ua, "User-Agent", wd->user_agent);
@@ -4484,8 +3917,8 @@ elm_map_user_agent_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
 
-   if (!wd) return NULL;
    return wd->user_agent;
 #else
    (void) obj;
@@ -4494,13 +3927,7 @@ elm_map_user_agent_get(const Evas_Object *obj)
 }
 
 EAPI Elm_Map_Route *
-elm_map_route_add(Evas_Object *obj,
-                  Elm_Map_Route_Type type,
-                  Elm_Map_Route_Method method,
-                  double flon,
-                  double flat,
-                  double tlon,
-                  double tlat)
+elm_map_route_add(Evas_Object *obj, Elm_Map_Route_Type type, Elm_Map_Route_Method method, double flon, double flat, double tlon, double tlat)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
@@ -4510,10 +3937,10 @@ elm_map_route_add(Evas_Object *obj,
    char *type_name = NULL;
    int fd;
 
-   if ((!wd) || (!wd->src)) return NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src, NULL);
 
    Elm_Map_Route *route = ELM_NEW(Elm_Map_Route);
-   if (!route) return NULL;
 
    snprintf(buf, sizeof(buf), DEST_ROUTE_XML_FILE);
    fd = mkstemp(buf);
@@ -4769,12 +4196,13 @@ elm_map_rotate_set(Evas_Object *obj, double degree, Evas_Coord cx, Evas_Coord cy
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    wd->rotate.d = degree;
    wd->rotate.cx = cx;
    wd->rotate.cy = cy;
-   wd->calc_job = ecore_job_add(_calc_job, wd);
+
+   evas_object_smart_changed(wd->pan_smart);
 #else
    (void) obj;
    (void) degree;
@@ -4789,8 +4217,8 @@ elm_map_rotate_get(const Evas_Object *obj, double *degree, Evas_Coord *cx, Evas_
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    if (degree) *degree = wd->rotate.d;
    if (cx) *cx = wd->rotate.cx;
    if (cy) *cy = wd->rotate.cy;
@@ -4808,12 +4236,12 @@ elm_map_wheel_disabled_set(Evas_Object *obj, Eina_Bool disabled)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype);
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
-   if (!wd) return;
    if ((!wd->wheel_disabled) && (disabled))
-     evas_object_event_callback_del_full(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
+     evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
    else if ((wd->wheel_disabled) && (!disabled))
-     evas_object_event_callback_add(wd->rect, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
+     evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
    wd->wheel_disabled = !!disabled;
 #else
    (void) obj;
@@ -4827,8 +4255,8 @@ elm_map_wheel_disabled_get(const Evas_Object *obj)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
    Widget_Data *wd = elm_widget_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
 
-   if (!wd) return EINA_FALSE;
    return wd->wheel_disabled;
 #else
    (void) obj;
@@ -4843,8 +4271,7 @@ elm_map_track_add(Evas_Object *obj, EMap_Route *emap)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
 
    Evas_Object *route = elm_route_add(obj);
    elm_route_emap_set(route, emap);
@@ -4865,8 +4292,7 @@ elm_map_track_remove(Evas_Object *obj, Evas_Object *route)
 #ifdef HAVE_ELEMENTARY_ECORE_CON
    ELM_CHECK_WIDTYPE(obj, widtype) ;
    Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return ;
+   EINA_SAFETY_ON_NULL_RETURN(wd);
 
    wd->track = eina_list_remove(wd->track, route);
    evas_object_del(route);
@@ -4875,118 +4301,3 @@ elm_map_track_remove(Evas_Object *obj, Evas_Object *route)
    (void) route;
 #endif
 }
-
-#ifdef HAVE_ELEMENTARY_ECORE_CON
-
-static char *
-_mapnik_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
-{
-   char buf[PATH_MAX];
-   // ((x+y+zoom)%3)+'a' is requesting map images from distributed tile servers (eg., a, b, c)
-   snprintf(buf, sizeof(buf), "http://%c.tile.openstreetmap.org/%d/%d/%d.png", ((x+y+zoom)%3)+'a', zoom, x, y);
-   return strdup(buf);
-}
-
-static char *
-_osmarender_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf), "http://%c.tah.openstreetmap.org/Tiles/tile/%d/%d/%d.png", ((x+y+zoom)%3)+'a', zoom, x, y);
-   return strdup(buf);
-}
-
-static char *
-_cyclemap_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf), "http://%c.tile.opencyclemap.org/cycle/%d/%d/%d.png", ((x+y+zoom)%3)+'a', zoom, x, y);
-   return strdup(buf);
-}
-
-static char *
-_mapquest_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf), "http://otile%d.mqcdn.com/tiles/1.0.0/osm/%d/%d/%d.png", ((x+y+zoom)%4)+1, zoom, x, y);
-   return strdup(buf);
-}
-
-static char *
-_mapquest_aerial_url_cb(Evas_Object *obj __UNUSED__, int x, int y, int zoom)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf), "http://oatile%d.mqcdn.com/naip/%d/%d/%d.png", ((x+y+zoom)%4)+1, zoom, x, y);
-   return strdup(buf);
-}
-
-static char *_yours_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf),
-            "%s?flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&v=%s&fast=%d&instructions=1",
-            ROUTE_YOURS_URL, flat, flon, tlat, tlon, type_name, method);
-
-   return strdup(buf);
-}
-
-// TODO: fix monav api
-/*
-static char *_monav_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf),
-            "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
-            ROUTE_MONAV_URL, flat, flon, tlat, tlon, type_name, method);
-
-   return strdup(buf);
-}
-*/
-
-// TODO: fix ors api
-/*
-static char *_ors_url_cb(Evas_Object *obj __UNUSED__, char *type_name, int method, double flon, double flat, double tlon, double tlat)
-{
-   char buf[PATH_MAX];
-   snprintf(buf, sizeof(buf),
-            "%s?flat=%f&flon=%f&tlat=%f&tlon=%f&v=%s&fast=%d&instructions=1",
-            ROUTE_ORS_URL, flat, flon, tlat, tlon, type_name, method);
-
-   return strdup(buf);
-}
-*/
-
-static char *
-_nominatim_url_cb(Evas_Object *obj, int method, char *name, double lon, double lat)
-{
-   ELM_CHECK_WIDTYPE(obj, widtype) strdup("");
-   Widget_Data *wd = elm_widget_data_get(obj);
-   char **str;
-   unsigned int ele, idx;
-   char search_url[PATH_MAX];
-   char buf[PATH_MAX];
-
-   if (!wd) return strdup("");
-   if (method == ELM_MAP_NAME_METHOD_SEARCH)
-     {
-        search_url[0] = '\0';
-        str = eina_str_split_full(name, " ", 0, &ele);
-        for (idx = 0 ; idx < ele ; idx++)
-          {
-             eina_strlcat(search_url, str[idx], sizeof(search_url));
-             if (!(idx == (ele-1))) eina_strlcat(search_url, "+", sizeof(search_url));
-          }
-        snprintf(buf, sizeof(buf), "%s/search?q=%s&format=xml&polygon=0&addressdetails=0", NAME_NOMINATIM_URL, search_url);
-
-        if (str && str[0])
-          {
-             free(str[0]);
-             free(str);
-          }
-     }
-   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);
-   else strcpy(buf, "");
-
-   return strdup(buf);
-}
-
-#endif