Merge remote-tracking branch 'remotes/origin/upstream'
[framework/uifw/elementary.git] / src / lib / elm_map.c
index 78f598a..dae8319 100644 (file)
@@ -13,6 +13,7 @@
 typedef struct _Widget_Data Widget_Data;
 typedef struct _Path Path;
 typedef struct _Color Color;
+typedef struct _Region Region;
 typedef struct _Pan Pan;
 typedef struct _Grid Grid;
 typedef struct _Grid_Item Grid_Item;
@@ -21,8 +22,10 @@ typedef struct _Overlay_Class Overlay_Class;
 typedef struct _Overlay_Group Overlay_Group;
 typedef struct _Overlay_Bubble Overlay_Bubble;
 typedef struct _Overlay_Route Overlay_Route;
-typedef struct _Marker_Group Marker_Group;
-typedef struct _Marker_Bubble Marker_Bubble;
+typedef struct _Overlay_Line Overlay_Line;
+typedef struct _Overlay_Polygon Overlay_Polygon;
+typedef struct _Overlay_Circle Overlay_Circle;
+typedef struct _Overlay_Scale Overlay_Scale;
 typedef struct _Path_Node Path_Node;
 typedef struct _Path_Waypoint Path_Waypoint;
 typedef struct _Route_Dump Route_Dump;
@@ -38,6 +41,7 @@ typedef int                        (*Elm_Map_Module_Tile_Zoom_Max_Func)(void);
 typedef char                      *(*Elm_Map_Module_Tile_Url_Func)(const Evas_Object *obj, int x, int y, int zoom);
 typedef Eina_Bool                  (*Elm_Map_Module_Tile_Geo_to_Coord_Func)(const Evas_Object *obj, int zoom, double lon, double lat, int size, int *x, int *y);
 typedef Eina_Bool                  (*Elm_Map_Module_Tile_Coord_to_Geo_Func)(const Evas_Object *obj, int zoom, int x, int y, int size, double *lon, double *lat);
+typedef double                     (*Elm_Map_Module_Tile_Scale_Func)(const Evas_Object *obj, double lon, double lat, int zoom);
 typedef char                      *(*Elm_Map_Module_Route_Url_Func)(const Evas_Object *obj, const char *type_name, int method, double flon, double flat, double tlon, double tlat);
 typedef char                      *(*Elm_Map_Module_Name_Url_Func)(const Evas_Object *obj, int method, const char *name, double lon, double lat);
 
@@ -98,6 +102,11 @@ struct _Path
    Evas_Coord x, y;
 };
 
+struct _Region
+{
+   double lon, lat;
+};
+
 struct _Delayed_Data
 {
    void (*func)(void *data);
@@ -105,11 +114,9 @@ struct _Delayed_Data
    Elm_Map_Zoom_Mode mode;
    int zoom;
    double lon, lat;
-   Eina_List *markers;
    Eina_List *overlays;
 };
 
-// Map Tile source
 // FIXME: Currently tile size must be 256*256
 // and the map size is pow(2.0, z) * (tile size)
 struct _Source_Tile
@@ -120,16 +127,15 @@ struct _Source_Tile
    Elm_Map_Module_Tile_Url_Func url_cb;
    Elm_Map_Module_Tile_Geo_to_Coord_Func geo_to_coord;
    Elm_Map_Module_Tile_Coord_to_Geo_Func coord_to_geo;
+   Elm_Map_Module_Tile_Scale_Func scale_cb;
 };
 
-// Map Route Source
 struct _Source_Route
 {
    const char *name;
    Elm_Map_Module_Route_Url_Func url_cb;
 };
 
-// Map Name Source
 struct _Source_Name
 {
    const char *name;
@@ -144,6 +150,7 @@ struct _Color
 struct _Overlay_Group
 {
    Widget_Data *wd;
+   double lon, lat;
    Elm_Map_Overlay *overlay; // virtual group type overlay
    Elm_Map_Overlay *clas;    // class overlay for this virtual group
    Overlay_Default *ovl;     // rendered overlay
@@ -198,91 +205,56 @@ struct _Overlay_Route
    Eina_List *nodes;
 };
 
-struct _Elm_Map_Overlay
+struct _Overlay_Line
 {
    Widget_Data *wd;
-
-   Eina_Bool paused : 1;
-   Eina_Bool hide : 1;
-   Evas_Coord zoom_min;
-   Color c;
-   void *data;               // user set data
-
-   Elm_Map_Overlay_Type type;
-   void *ovl;                 // Overlay Data for each type
-
-   Elm_Map_Overlay_Get_Cb cb;
-   void *cb_data;
-
-   // These are not used if overlay type is class or group
-   Overlay_Group *grp;
-};
-
-struct _Elm_Map_Marker_Class
-{
-   const char *style;
-   struct _Elm_Map_Marker_Class_Func
-     {
-        Elm_Map_Marker_Get_Func get;
-        Elm_Map_Marker_Del_Func del; //if NULL the object will be destroyed with evas_object_del()
-        Elm_Map_Marker_Icon_Get_Func icon_get;
-     } func;
+   double flon, flat, tlon, tlat;
+   Evas_Object *obj;
 };
 
-struct _Elm_Map_Group_Class
+struct _Overlay_Polygon
 {
    Widget_Data *wd;
-
-   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;
-   struct
-     {
-        Elm_Map_Group_Icon_Get_Func icon_get;
-     } func;
-
-   Eina_Bool hide : 1;
+   Eina_List *regions;  // list of Regions
+   Evas_Object *obj;
 };
 
-struct _Marker_Bubble
+struct _Overlay_Circle
 {
    Widget_Data *wd;
-   Evas_Object *pobj;
-   Evas_Object *obj, *sc, *bx;
+   double lon, lat;
+   double radius;    // Intial pixel in intial view
+   double ratio;    // initial-radius/map-size
+   Evas_Object *obj;
 };
 
-struct _Elm_Map_Marker
+struct _Overlay_Scale
 {
    Widget_Data *wd;
-   Elm_Map_Marker_Class *clas;
-   Elm_Map_Group_Class *group_clas;
-   double longitude, latitude;
+   Evas_Coord x, y;
    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
+struct _Elm_Map_Overlay
 {
    Widget_Data *wd;
-   Elm_Map_Group_Class *clas;
-   Evas_Coord w, h;
-   Evas_Object *obj;
 
-   Evas_Coord x, y;
-   Eina_List *markers;
+   Eina_Bool visible : 1;
+   Eina_Bool paused : 1;
+   Eina_Bool hide : 1;
+   Evas_Coord zoom_min;
+   Color c;
+   void *data;               // user set data
 
-   Marker_Bubble *bubble;
+   Elm_Map_Overlay_Type type;
+   void *ovl;                 // Overlay Data for each type
+
+   Elm_Map_Overlay_Get_Cb cb;
+   void *cb_data;
+
+   // These are not used if overlay type is class or group
+   Overlay_Group *grp;
 };
 
 struct _Elm_Map_Route
@@ -397,7 +369,7 @@ struct _Widget_Data
    Evas_Object *scr;
    Evas_Object *ges;
    Evas_Object *pan_smart;
-   Evas_Object *sep_maps_markers; // Tiles are below this and overlays are on top
+   Evas_Object *sep_maps_overlays; // Tiles are below this and overlays are on top
    Evas_Map *map;
 
    Eina_Array *src_tile_mods;
@@ -423,8 +395,6 @@ struct _Widget_Data
 
    int zoom;
    double zoom_detail;
-   double prev_lon, prev_lat;
-   Evas_Coord ox, oy;
    struct
      {
         int w, h;  // Current pixel width, heigth of a grid
@@ -466,17 +436,13 @@ struct _Widget_Data
 
    Eina_Bool wheel_disabled : 1;
 
-   unsigned int markers_max_num;
-   Eina_Bool paused_markers : 1;
-   Eina_List *group_classes;
-   Eina_List *marker_classes;
-   Eina_List *markers;
-
    Eina_List *routes;
    Eina_List *track;
    Eina_List *names;
 
    Eina_List *overlays;
+   Eina_List *group_overlays;
+   Eina_List *all_overlays;
 };
 
 static char *_mapnik_url_cb(const Evas_Object *obj __UNUSED__, int x, int y, int zoom);
@@ -490,14 +456,15 @@ static char *_nominatim_url_cb(const Evas_Object *obj, int method, const char *n
 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 double _scale_cb(const Evas_Object *obj __UNUSED__, double lon __UNUSED__, double lat, int zoom);
 
 const Source_Tile src_tiles[] =
 {
-   {"Mapnik", 0, 18, _mapnik_url_cb, NULL, NULL},
-   {"Osmarender", 0, 17, _osmarender_url_cb, NULL, NULL},
-   {"CycleMap", 0, 16, _cyclemap_url_cb, NULL, NULL},
-   {"MapQuest", 0, 18, _mapquest_url_cb, NULL, NULL},
-   {"MapQuest Open Aerial", 0, 11, _mapquest_aerial_url_cb, NULL, NULL},
+   {"Mapnik", 0, 18, _mapnik_url_cb, NULL, NULL, _scale_cb},
+   {"Osmarender", 0, 17, _osmarender_url_cb, NULL, NULL, _scale_cb},
+   {"CycleMap", 0, 16, _cyclemap_url_cb, NULL, NULL, _scale_cb},
+   {"MapQuest", 0, 18, _mapquest_url_cb, NULL, NULL, _scale_cb},
+   {"MapQuest Open Aerial", 0, 11, _mapquest_aerial_url_cb, NULL, NULL, _scale_cb}
 };
 
 // FIXME: Fix more open sources
@@ -508,6 +475,20 @@ const Source_Route src_routes[] =
    //{"ORS", _ors_url_cb},     // http://www.openrouteservice.org
 };
 
+// Refer : http://wiki.openstreetmap.org/wiki/FAQ
+// meters per pixel when latitude is 0 (equator)
+// meters per pixel  = _osm_scale_meter[zoom] * cos (latitude)
+const double _osm_scale_meter[] =
+{78206, 39135.758482, 19567.879241, 9783.939621, 4891.969810,
+ 2445.984905, 1222.992453, 611.496226, 305.748113, 152.874057, 76.437028,
+ 38.218514, 19.109257, 9.554629, 4.777314, 2.388657, 1.194329, 0.597164,
+ 0.29858};
+
+// Scale in meters
+const double _scale_tb[] =
+{10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000, 50000,
+ 20000, 10000, 5000, 2000, 1000, 500, 500, 200, 100, 50, 20, 10, 5, 2, 1};
+
 // FIXME: Add more open sources
 const Source_Name src_names[] =
 {
@@ -532,6 +513,7 @@ static const char SIG_SCROLL_ANIM_STOP[] =   "scroll,anim,stop";
 static const char SIG_ZOOM_START[] =         "zoom,start";
 static const char SIG_ZOOM_STOP[] =          "zoom,stop";
 static const char SIG_ZOOM_CHANGE[] =        "zoom,change";
+static const char SIG_LOADED[] =               "loaded";
 static const char SIG_TILE_LOAD[] =          "tile,load";
 static const char SIG_TILE_LOADED[] =        "tile,loaded";
 static const char SIG_TILE_LOADED_FAIL[] =   "tile,loaded,fail";
@@ -555,6 +537,7 @@ static const Evas_Smart_Cb_Description _signals[] = {
        {SIG_ZOOM_START, ""},
        {SIG_ZOOM_STOP, ""},
        {SIG_ZOOM_CHANGE, ""},
+       {SIG_LOADED, ""},
        {SIG_TILE_LOAD, ""},
        {SIG_TILE_LOADED, ""},
        {SIG_TILE_LOADED_FAIL, ""},
@@ -569,7 +552,7 @@ static const Evas_Smart_Cb_Description _signals[] = {
 };
 
 static void
-_edj_marker_size_get(Widget_Data *wd, Evas_Coord *w, Evas_Coord *h)
+_edj_overlay_size_get(Widget_Data *wd, Evas_Coord *w, Evas_Coord *h)
 {
    EINA_SAFETY_ON_NULL_RETURN(wd);
    EINA_SAFETY_ON_NULL_RETURN(w);
@@ -658,7 +641,6 @@ _region_to_coord_convert(Widget_Data *wd, double lon, double lat, Evas_Coord siz
      {
         if (wd->src_tile->geo_to_coord(wd->obj, zoom, lon, lat, size, x, y)) return;
      }
-
    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)))
@@ -731,419 +713,6 @@ _region_show(void *data)
 }
 
 static void
-_bubble_update(Marker_Bubble *bubble, Eina_List *contents)
-{
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-   EINA_SAFETY_ON_NULL_RETURN(contents);
-
-   Eina_List *l;
-   Evas_Object *c;
-
-   elm_box_clear(bubble->bx);
-   EINA_LIST_FOREACH(contents, l, c) elm_box_pack_end(bubble->bx, c);
-}
-
-static void
-_bubble_place(Marker_Bubble *bubble)
-{
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-
-   Evas_Coord x, y, w, h;
-   Evas_Coord xx, yy, ww, hh;
-   const char *s;
-
-   if ((!bubble->obj) || (!bubble->pobj)) return;
-   evas_object_geometry_get(bubble->pobj, &x, &y, &w, NULL);
-
-   s = edje_object_data_get(bubble->obj, "size_w");
-   if (s) ww = atoi(s);
-   else ww = 0;
-
-   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;
-
-   xx = x + (w / 2) - (ww / 2);
-   yy = y - hh;
-
-   _obj_place(bubble->obj, xx, yy, ww, hh);
-   evas_object_raise(bubble->obj);
-}
-
-static void
-_bubble_sc_hints_changed_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(data);
-}
-
-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);
-}
-
-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);
-}
-
-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);
-}
-
-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);
-}
-
-static void
-_bubble_free(Marker_Bubble* bubble)
-{
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-
-   evas_object_del(bubble->bx);
-   evas_object_del(bubble->sc);
-   evas_object_del(bubble->obj);
-   free(bubble);
-}
-
-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
-_marker_group_update(Marker_Group* group, Elm_Map_Group_Class *clas, Eina_List *markers)
-{
-   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)
-     {
-        sum_x += marker->x;
-        sum_y += marker->y;
-        cnt++;
-     }
-
-   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;
-
-   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 (clas->func.icon_get)
-     {
-        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);
-     }
-   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 *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
-_marker_group_bubble_open_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
-{
-   EINA_SAFETY_ON_NULL_RETURN(data);
-   Marker_Group *group = data;
-   Eina_List *l;
-   Elm_Map_Marker *marker;
-   Eina_List *contents = NULL;
-
-   if (!group->bubble) group->bubble = _bubble_create(group->obj, group->wd);
-
-   EINA_LIST_FOREACH(group->markers, l, marker)
-     {
-        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
-_marker_group_bringin_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *soure __UNUSED__)
-{
-   EINA_SAFETY_ON_NULL_RETURN(data);
-
-   double lon, lat;
-   Marker_Group *group = data;
-   _coord_to_region_convert(group->wd, group->x, group->y, group->wd->size.w,
-                         &lon, &lat);
-   elm_map_region_bring_in(group->wd->obj, lon, lat);
-}
-
-static void
-_marker_group_free(Marker_Group* group)
-{
-   EINA_SAFETY_ON_NULL_RETURN(group);
-
-   if (group->bubble) _bubble_free(group->bubble);
-
-   eina_list_free(group->markers);
-   evas_object_del(group->obj);
-
-   free(group);
-}
-
-static Marker_Group*
-_marker_group_create(Widget_Data *wd)
-{
-   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
-
-   Marker_Group *group = ELM_NEW(Marker_Group);
-
-   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;
-}
-
-static void
-_marker_update(Elm_Map_Marker *marker)
-{
-   EINA_SAFETY_ON_NULL_RETURN(marker);
-   Elm_Map_Marker_Class *clas = marker->clas;
-   EINA_SAFETY_ON_NULL_RETURN(clas);
-
-   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));
-
-   if (clas->func.icon_get)
-     {
-        Evas_Object *icon = NULL;
-
-        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);
-     }
-   _region_to_coord_convert(marker->wd, 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)
-          {
-             Eina_List *contents = NULL;
-             contents = eina_list_append(contents, marker->content);
-             _bubble_update(marker->bubble, contents);
-          }
-      }
-}
-
-
-
-static void
-_marker_place(Widget_Data *wd)
-{
-   EINA_SAFETY_ON_NULL_RETURN(wd);
-
-   Eina_List *l;
-
-   Elm_Map_Marker *marker;
-   Elm_Map_Group_Class *group_clas;
-
-   Evas_Coord gw, gh;
-
-   if (wd->paused_markers || (!eina_list_count(wd->markers))) return;
-
-   _edj_marker_size_get(wd, &gw, &gh);
-   gw *= 2;
-   gh *= 2;
-
-   EINA_LIST_FOREACH(wd->markers, l, marker)
-     {
-        _marker_update(marker);
-        marker->grouped = EINA_FALSE;
-        marker->leader = EINA_FALSE;
-     }
-
-   EINA_LIST_FOREACH(wd->group_classes, l, group_clas)
-     {
-        Eina_List *ll;
-        EINA_LIST_FOREACH(group_clas->markers, ll, marker)
-          {
-             Eina_List *lll;
-             Elm_Map_Marker *mm;
-             Eina_List *markers = NULL;
-
-             if (marker->grouped) continue;
-             if (group_clas->zoom_grouped < wd->zoom)
-               {
-                  marker->grouped = EINA_FALSE;
-                  continue;
-               }
-
-             EINA_LIST_FOREACH(group_clas->markers, lll, mm)
-               {
-                  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_LIST_FOREACH(wd->markers, l, marker)
-     {
-
-        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_to_canvas(wd, marker->x, marker->y, &x, &y);
-             _obj_place(marker->obj, x - (marker->w / 2), y - (marker->h / 2),
-                         marker->w, marker->h);
-          }
-     }
-
-   EINA_LIST_FOREACH(wd->markers, l, marker)
-     {
-        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
-          {
-             Evas_Coord x, y;
-             _coord_to_canvas(wd, group->x, group->y, &x, &y);
-             _obj_place(group->obj, x - (group->w / 2), y - (group->h / 2),
-                         group->w, group->h);
-          }
-     }
-}
-
-static void
 _grid_item_coord_get(Grid_Item *gi, int *x, int *y, int *w, int *h)
 {
    EINA_SAFETY_ON_NULL_RETURN(gi);
@@ -1249,7 +818,7 @@ _grid_item_create(Grid *g, Evas_Coord x, Evas_Coord y)
    evas_object_image_filled_set(gi->img, EINA_TRUE);
    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);
+   evas_object_stack_below(gi->img, g->wd->sep_maps_overlays);
 
    snprintf(buf, sizeof(buf), CACHE_TILE_ROOT, g->wd->id, g->zoom, x);
    snprintf(buf2, sizeof(buf2), CACHE_TILE_PATH, buf, y);
@@ -1305,8 +874,11 @@ _downloaded_cb(void *data, const char *file __UNUSED__, int status)
    gi->job = NULL;
    gi->wd->download_num--;
    if (!gi->wd->download_num)
-      edje_object_signal_emit(elm_smart_scroller_edje_object_get(gi->wd->scr),
-                              "elm,state,busy,stop", "elm");
+     {
+        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, NULL);
+     }
 }
 
 static Eina_Bool
@@ -1344,7 +916,7 @@ _download_job(void *data)
              wd->download_list = eina_list_remove(wd->download_list, gi);
              wd->try_num++;
              wd->download_num++;
-             evas_object_smart_callback_call(gi->wd->obj, SIG_TILE_LOAD,
+             evas_object_smart_callback_call(wd->obj, SIG_TILE_LOAD,
                                              NULL);
              if (wd->download_num == 1)
                 edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
@@ -1514,9 +1086,9 @@ _track_place(Widget_Data *wd)
         _region_to_coord_convert(wd, lon_min, lat_max, size, &xmin, &ymin);
         _region_to_coord_convert(wd, lon_max, lat_min, size, &xmax, &ymax);
 
-        if( !(xmin < px && xmax < px) && !(xmin > px+ow && xmax > px+ow))
+        if ( !(xmin < px && xmax < px) && !(xmin > px+ow && xmax > px+ow))
         {
-           if( !(ymin < py && ymax < py) && !(ymin > py+oh && ymax > py+oh))
+           if ( !(ymin < py && ymax < py) && !(ymin > py+oh && ymax > py+oh))
            {
               //display the route
               evas_object_move(route, xmin - px, ymin - py);
@@ -1587,6 +1159,8 @@ static void
 zoom_do(Widget_Data *wd, double zoom)
 {
    EINA_SAFETY_ON_NULL_RETURN(wd);
+   if (zoom > wd->src_tile->zoom_max) zoom = wd->src_tile->zoom_max;
+   else if (zoom < wd->src_tile->zoom_min) zoom = wd->src_tile->zoom_min;
    if (zoom > wd->zoom_max) zoom = wd->zoom_max;
    else if (zoom < wd->zoom_min) zoom = wd->zoom_min;
 
@@ -1784,7 +1358,7 @@ _mouse_wheel_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, voi
 
    if (!wd->paused)
      {
-        Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel*) event_info;
+        Evas_Event_Mouse_Wheel *ev = event_info;
         zoom_do(wd, wd->zoom_detail - ((double)ev->z / 10));
     }
 }
@@ -2045,12 +1619,12 @@ _overlay_default_new(Elm_Map_Overlay *overlay, double lon, double lat, Color c,
 
    Overlay_Default *ovl = ELM_NEW(Overlay_Default);
    ovl->wd = overlay->wd;
-   _edj_marker_size_get(ovl->wd, &(ovl->w), &(ovl->h));
+   _edj_overlay_size_get(ovl->wd, &(ovl->w), &(ovl->h));
    ovl->w *= scale;
    ovl->h *= scale;
    ovl->layout = elm_layout_add(ovl->wd->obj);
    evas_object_smart_member_add(ovl->layout, ovl->wd->pan_smart);
-   evas_object_stack_above(ovl->layout, ovl->wd->sep_maps_markers);
+   evas_object_stack_above(ovl->layout, ovl->wd->sep_maps_overlays);
    elm_layout_theme_set(ovl->layout, "map/marker", "radio",
                         elm_widget_style_get(ovl->wd->obj));
    evas_object_event_callback_add(ovl->layout, EVAS_CALLBACK_MOUSE_DOWN,
@@ -2080,9 +1654,11 @@ _overlay_group_coord_member_update(Overlay_Group *grp, Evas_Coord x, Evas_Coord
 {
    EINA_SAFETY_ON_NULL_RETURN(grp);
    if (!grp->ovl) return;
-   char text[32];
 
+   char text[32];
    _overlay_default_coord_set(grp->ovl, x, y);
+   _coord_to_region_convert(grp->wd, x, y, grp->wd->size.w, &grp->lon, &grp->lat);
+
    if (grp->members) eina_list_free(grp->members);
    grp->members = members;
    snprintf(text, sizeof(text), "%d", eina_list_count(members));
@@ -2090,16 +1666,6 @@ _overlay_group_coord_member_update(Overlay_Group *grp, Evas_Coord x, Evas_Coord
 }
 
 static void
-_overlay_group_region_get(Overlay_Group *grp, double *lon, double *lat)
-{
-   EINA_SAFETY_ON_NULL_RETURN(grp);
-   Evas_Coord xx, yy;
-   _overlay_default_coord_get(grp->ovl, &xx, &yy, NULL, NULL);
-   _coord_to_canvas(grp->wd, xx, yy, &xx, &yy);
-   elm_map_canvas_to_region_convert(grp->wd->obj, xx, yy, lon, lat);
-}
-
-static void
 _overlay_group_icon_update(Overlay_Group *grp, const Evas_Object *icon)
 {
    EINA_SAFETY_ON_NULL_RETURN(grp);
@@ -2264,17 +1830,22 @@ _overlay_class_new(Widget_Data *wd)
 }
 
 static void
-_overlay_bubble_hide(Overlay_Bubble *bubble)
-{
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-   if (bubble->obj) evas_object_hide(bubble->obj);
-}
-
-static void
 _overlay_bubble_coord_update(Overlay_Bubble *bubble)
 {
    EINA_SAFETY_ON_NULL_RETURN(bubble);
-   if (!(bubble->pobj))
+   if (bubble->pobj)
+     {
+        Evas_Coord x, y, w, h;
+        evas_object_geometry_get(bubble->pobj, &x, &y, &w, &h);
+        bubble->x = x + (w / 2);
+        bubble->y = y - (bubble->h / 2);
+        _canvas_to_coord(bubble->wd, bubble->x, bubble->y,
+                         &(bubble->x), &(bubble->y));
+        _coord_to_region_convert(bubble->wd, bubble->x, bubble->y,
+                                 bubble->wd->size.w,
+                                 &(bubble->lon), &(bubble->lat));
+     }
+   else
      {
         _region_to_coord_convert(bubble->wd, bubble->lon, bubble->lat,
                               bubble->wd->size.w, &bubble->x, &bubble->y);
@@ -2301,45 +1872,27 @@ _overlay_bubble_coord_get(Overlay_Bubble *bubble, Evas_Coord *x, Evas_Coord *y,
      }
 }
 
-static void
-_overlay_bubble_show(Overlay_Bubble *bubble)
+static Eina_Bool
+_overlay_bubble_show_hide(Overlay_Bubble *bubble, Eina_Bool visible)
 {
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-   if (!(bubble->pobj))
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bubble, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bubble->obj, EINA_FALSE);
+
+   if (!visible) evas_object_hide(bubble->obj);
+   else if (bubble->pobj && !evas_object_visible_get(bubble->pobj))
+     {
+        evas_object_hide(bubble->obj);
+        visible = EINA_FALSE;
+     }
+   else
      {
         _coord_to_canvas(bubble->wd, bubble->x, bubble->y,
-                           &(bubble->x), &(bubble->y));
+                         &(bubble->x), &(bubble->y));
         _obj_place(bubble->obj, bubble->x - (bubble->w /2),
                    bubble->y - (bubble->h /2), bubble->w, bubble->h);
+        evas_object_raise(bubble->obj);
      }
-}
-
-static void
-_overlay_bubble_chase(Overlay_Bubble *bubble)
-{
-   EINA_SAFETY_ON_NULL_RETURN(bubble);
-   EINA_SAFETY_ON_NULL_RETURN(bubble->pobj);
-
-   Evas_Coord x, y, w;
-   evas_object_geometry_get(bubble->pobj, &x, &y, &w, NULL);
-   x = x + (w / 2) - (bubble->w / 2);
-   y = y - bubble->h;
-   _obj_place(bubble->obj, x, y, bubble->w, bubble->h);
-   evas_object_raise(bubble->obj);
-}
-
-static void
-_overlay_bubble_hide_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
-{
-   EINA_SAFETY_ON_NULL_RETURN(data);
-   _overlay_bubble_hide(data);
-}
-
-static void
-_overlay_bubble_chase_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
-{
-   EINA_SAFETY_ON_NULL_RETURN(data);
-   _overlay_bubble_chase(data);
+   return visible;
 }
 
 static void
@@ -2350,15 +1903,6 @@ _overlay_bubble_free(Overlay_Bubble* bubble)
    evas_object_del(bubble->bx);
    evas_object_del(bubble->sc);
    evas_object_del(bubble->obj);
-   if (bubble->pobj)
-     {
-        evas_object_event_callback_del_full(bubble->pobj, EVAS_CALLBACK_HIDE,
-                                            _overlay_bubble_hide_cb, bubble);
-        evas_object_event_callback_del_full(bubble->pobj, EVAS_CALLBACK_SHOW,
-                                            _overlay_bubble_chase_cb, bubble);
-        evas_object_event_callback_del_full(bubble->pobj, EVAS_CALLBACK_MOVE,
-                                            _overlay_bubble_chase_cb, bubble);
-     }
    free(bubble);
 }
 
@@ -2375,8 +1919,6 @@ _overlay_bubble_new(Elm_Map_Overlay *overlay)
    bubble->obj = edje_object_add(evas_object_evas_get(overlay->wd->obj));
    _elm_theme_object_set(overlay->wd->obj, bubble->obj , "map", "marker_bubble",
                          elm_widget_style_get(overlay->wd->obj));
-   evas_object_event_callback_add(bubble->obj, EVAS_CALLBACK_MOUSE_UP,
-                                      _overlay_bubble_chase_cb, bubble);
    evas_object_event_callback_add(bubble->obj, EVAS_CALLBACK_MOUSE_DOWN,
                                      _overlay_clicked_cb, overlay);
 
@@ -2455,52 +1997,297 @@ _overlay_route_show(Overlay_Route *r)
 }
 
 static void
-_overlay_route_free(Overlay_Route* route)
+_overlay_route_free(Overlay_Route* route)
+{
+   EINA_SAFETY_ON_NULL_RETURN(route);
+   Path *p;
+   Path_Node *n;
+
+   evas_object_del(route->obj);
+   EINA_LIST_FREE(route->paths, p)  free(p);
+   EINA_LIST_FREE(route->nodes, n)
+     {
+        if (n->pos.address) eina_stringshare_del(n->pos.address);
+        free(n);
+     }
+   free(route);
+}
+
+static Overlay_Route *
+_overlay_route_new(Widget_Data *wd, const Elm_Map_Route *route, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(route, NULL);
+
+   Eina_List *l;
+   Path_Node *n;
+
+   Overlay_Route *ovl = ELM_NEW(Overlay_Route);
+   ovl->wd = wd;
+   ovl->obj = evas_object_polygon_add(evas_object_evas_get(wd->obj));
+   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
+   _overlay_route_color_update(ovl, c);
+
+   EINA_LIST_FOREACH(route->nodes, l, n)
+     {
+        Path *path;
+        Path_Node *node;
+
+        node = ELM_NEW(Path_Node);
+        node->idx = n->idx;
+        node->pos.lon = n->pos.lon;
+        node->pos.lat = n->pos.lat;
+        if (n->pos.address) node->pos.address = strdup(n->pos.address);
+        ovl->nodes = eina_list_append(ovl->nodes, node);
+
+        path = ELM_NEW(Path);
+        ovl->paths = eina_list_append(ovl->paths, path);
+     }
+   return ovl;
+}
+
+static void
+_overlay_line_color_update(Overlay_Line *ovl, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_color_set(ovl->obj, c.r, c.g, c.b, c.a);
+}
+
+static void
+_overlay_line_hide(Overlay_Line *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   if (ovl->obj) evas_object_hide(ovl->obj);
+}
+
+static void
+_overlay_line_show(Overlay_Line *ovl)
+{
+   Evas_Coord fx, fy, tx, ty;
+   Widget_Data *wd = ovl->wd;
+
+   _region_to_coord_convert(wd, ovl->flon, ovl->flat, wd->size.w, &fx, &fy);
+   _region_to_coord_convert(wd, ovl->tlon, ovl->tlat, wd->size.w, &tx, &ty);
+   _coord_to_canvas(wd, fx, fy, &fx, &fy);
+   _coord_to_canvas(wd, tx, ty, &tx, &ty);
+   evas_object_line_xy_set(ovl->obj, fx, fy, tx, ty);
+   evas_object_show(ovl->obj);
+}
+
+static void
+_overlay_line_free(Overlay_Line *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_del(ovl->obj);
+   free(ovl);
+}
+
+static Overlay_Line *
+_overlay_line_new(Widget_Data *wd, double flon, double flat, double tlon, double tlat, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+
+   Overlay_Line *ovl = ELM_NEW(Overlay_Line);
+   ovl->wd = wd;
+   ovl->flon = flon;
+   ovl->flat = flat;
+   ovl->tlon = tlon;
+   ovl->tlat = tlat;
+   ovl->obj = evas_object_line_add(evas_object_evas_get(wd->obj));
+   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
+   _overlay_line_color_update(ovl, c);
+   return ovl;
+}
+
+static void
+_overlay_polygon_color_update(Overlay_Polygon *ovl, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_color_set(ovl->obj, c.r, c.g, c.b, c.a);
+}
+
+static void
+_overlay_polygon_hide(Overlay_Polygon *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   if (ovl->obj) evas_object_hide(ovl->obj);
+}
+
+static void
+_overlay_polygon_show(Overlay_Polygon *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   Eina_List *l;
+   Region *r;
+   Widget_Data *wd = ovl->wd;
+
+   evas_object_polygon_points_clear(ovl->obj);
+   EINA_LIST_FOREACH(ovl->regions, l, r)
+     {
+        Evas_Coord x, y;
+        _region_to_coord_convert(wd, r->lon, r->lat, wd->size.w, &x, &y);
+        _coord_to_canvas(wd, x, y, &x, &y);
+        evas_object_polygon_point_add(ovl->obj, x, y);
+     }
+   evas_object_show(ovl->obj);
+}
+
+static void
+_overlay_polygon_free(Overlay_Polygon *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   Region *r;
+   evas_object_del(ovl->obj);
+   EINA_LIST_FREE(ovl->regions, r) free(r);
+   free(ovl);
+}
+
+static Overlay_Polygon *
+_overlay_polygon_new(Widget_Data *wd, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+
+   Overlay_Polygon *ovl = ELM_NEW(Overlay_Polygon);
+   ovl->wd = wd;
+   ovl->obj = evas_object_polygon_add(evas_object_evas_get(wd->obj));
+   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
+   _overlay_polygon_color_update(ovl, c);
+   return ovl;
+}
+
+static void
+_overlay_circle_color_update(Overlay_Circle *ovl, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   Evas_Object *obj = elm_layout_edje_get(ovl->obj);
+   evas_object_color_set(obj, c.r, c.g, c.b, c.a);
+}
+
+static void
+_overlay_circle_hide(Overlay_Circle *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   if (ovl->obj) evas_object_hide(ovl->obj);
+}
+
+static void
+_overlay_circle_show(Overlay_Circle *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   double r;
+   Evas_Coord x, y;
+   Widget_Data *wd = ovl->wd;
+
+   r = (ovl->ratio) * wd->size.w;
+   _region_to_coord_convert(wd, ovl->lon, ovl->lat, wd->size.w, &x, &y);
+   _coord_to_canvas(wd, x, y, &x, &y);
+   _obj_place(ovl->obj, x - r, y - r, r * 2, r * 2);
+}
+
+static void
+_overlay_circle_free(Overlay_Circle *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_del(ovl->obj);
+   free(ovl);
+}
+
+static Overlay_Circle *
+_overlay_circle_new(Widget_Data *wd, double lon, double lat, double radius, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+
+   Overlay_Circle *ovl = ELM_NEW(Overlay_Circle);
+   ovl->wd = wd;
+   ovl->lon = lon;
+   ovl->lat = lat;
+   ovl->radius = radius;
+   ovl->ratio = radius / wd->size.w;
+
+   ovl->obj = elm_layout_add(wd->obj);
+   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
+   evas_object_stack_above(ovl->obj, wd->sep_maps_overlays);
+   elm_layout_theme_set(ovl->obj, "map/circle", "base",
+                        elm_widget_style_get(wd->obj));
+   _overlay_circle_color_update(ovl, c);
+   return ovl;
+}
+
+static void
+_overlay_scale_color_update(Overlay_Scale *ovl, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_color_set(ovl->obj, c.r, c.g, c.b, c.a);
+}
+
+static void
+_overlay_scale_hide(Overlay_Scale *ovl)
 {
-   EINA_SAFETY_ON_NULL_RETURN(route);
-   Path *p;
-   Path_Node *n;
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   if (ovl->obj) evas_object_hide(ovl->obj);
+}
 
-   evas_object_del(route->obj);
-   EINA_LIST_FREE(route->paths, p)  free(p);
-   EINA_LIST_FREE(route->nodes, n)
+ static void
+_overlay_scale_show(Overlay_Scale *ovl)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   Evas_Coord  w;
+   double lon, lat;
+   double text;
+   char buf[32];
+   double meter;
+   Widget_Data *wd = ovl->wd;
+
+   if ((int)sizeof(_scale_tb) <= wd->zoom)
      {
-        if (n->pos.address) eina_stringshare_del(n->pos.address);
-        free(n);
+        ERR("Zoom level is too high");
+        return;
      }
-   free(route);
+
+   elm_map_region_get(wd->obj, &lon, &lat);
+   meter = wd->src_tile->scale_cb(wd->obj, lon, lat, wd->zoom);
+
+   w = (_scale_tb[wd->zoom] / meter) * (wd->zoom_detail - wd->zoom + 1);
+
+   text = _scale_tb[wd->zoom]/1000;
+   if (text < 1)  snprintf(buf, sizeof(buf), "%d m", (int)(text * 1000));
+   else   snprintf(buf, sizeof(buf), "%d km", (int)text);
+
+   edje_object_part_text_set(elm_layout_edje_get(ovl->obj), "elm.text", buf);
+   _obj_place(ovl->obj, ovl->x, ovl->y, w, ovl->h);
 }
 
-static Overlay_Route *
-_overlay_route_new(Widget_Data *wd, const Elm_Map_Route *route, Color c)
+ static void
+_overlay_scale_free(Overlay_Scale *ovl)
 {
-   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(route, NULL);
+   EINA_SAFETY_ON_NULL_RETURN(ovl);
+   evas_object_del(ovl->obj);
+   free(ovl);
+}
 
-   Eina_List *l;
-   Path_Node *n;
+static Overlay_Scale *
+_overlay_scale_new(Widget_Data *wd, Evas_Coord x, Evas_Coord y, Color c)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+   const char *s;
 
-   Overlay_Route *ovl = ELM_NEW(Overlay_Route);
+   Overlay_Scale *ovl = ELM_NEW(Overlay_Scale);
    ovl->wd = wd;
-   ovl->obj = evas_object_polygon_add(evas_object_evas_get(wd->obj));
-   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
-   _overlay_route_color_update(ovl, c);
-
-   EINA_LIST_FOREACH(route->nodes, l, n)
-     {
-        Path *path;
-        Path_Node *node;
-
-        node = ELM_NEW(Path_Node);
-        node->idx = n->idx;
-        node->pos.lon = n->pos.lon;
-        node->pos.lat = n->pos.lat;
-        if (n->pos.address) node->pos.address = strdup(n->pos.address);
-        ovl->nodes = eina_list_append(ovl->nodes, node);
+   ovl->x = x;
+   ovl->y = y;
 
-        path = ELM_NEW(Path);
-        ovl->paths = eina_list_append(ovl->paths, path);
-     }
+   ovl->obj = elm_layout_add(wd->obj);
+   evas_object_smart_member_add(ovl->obj, wd->pan_smart);
+   evas_object_stack_above(ovl->obj, wd->sep_maps_overlays);
+   elm_layout_theme_set(ovl->obj, "map/scale", "base",
+                        elm_widget_style_get(wd->obj));
+   s = edje_object_data_get(elm_layout_edje_get(ovl->obj), "size_w");
+   if (s) ovl->w = atoi(s);
+   else ovl->w = 100;
+   s = edje_object_data_get(elm_layout_edje_get(ovl->obj), "size_h");
+   if (s) ovl->h = atoi(s);
+   else ovl->h = 60;
+   _overlay_scale_color_update(ovl, c);
    return ovl;
 }
 
@@ -2558,6 +2345,10 @@ _overlay_grouping(Eina_List *clas_membs, Elm_Map_Overlay *boss)
         sum_y = (sum_y + by) / (cnt + 1);
         grp_membs = eina_list_append(grp_membs, boss);
         _overlay_group_coord_member_update(boss->grp, sum_x, sum_y, grp_membs);
+
+        // Append group to all overlay list
+        boss->wd->group_overlays = eina_list_append(boss->wd->group_overlays,
+                                                  boss->grp->overlay);
      }
 }
 
@@ -2565,34 +2356,68 @@ static void
 _overlay_show(Elm_Map_Overlay *overlay)
 {
    Widget_Data *wd = overlay->wd;
-   Eina_Bool hide = EINA_FALSE;
-
-   if (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS) return;
 
    if (overlay->paused) return;
-   if ((overlay->grp->clas) &&  (overlay->grp->clas->paused)) return;
+   if ((overlay->grp) && (overlay->grp->clas) &&
+       (overlay->grp->clas->paused)) return;
+
+   overlay->visible = EINA_TRUE;
+   if (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS)
+     {
+        overlay->visible = EINA_FALSE;
+        return;
+     }
+   if (overlay->grp)
+     {
+        if ((overlay->grp->in) ||
+            (overlay->hide) || (overlay->zoom_min > wd->zoom))
+           overlay->visible = EINA_FALSE;
 
-   if (((overlay->grp->in) || (overlay->hide) ||
-       (overlay->zoom_min > wd->zoom)))
-      hide = EINA_TRUE;
-   if ((overlay->grp->clas) && ((overlay->grp->clas->hide) ||
-       (overlay->grp->clas->zoom_min > wd->zoom)))
-      hide = EINA_TRUE;
+        if ((overlay->grp->clas) &&
+            ((overlay->grp->clas->hide) ||
+             (overlay->grp->clas->zoom_min > wd->zoom)))
+           overlay->visible = EINA_FALSE;
+     }
 
    if (overlay->type == ELM_MAP_OVERLAY_TYPE_DEFAULT)
      {
-        if (hide) _overlay_default_hide(overlay->ovl);
-        else _overlay_default_show(overlay->ovl);
+        if (overlay->visible) _overlay_default_show(overlay->ovl);
+        else _overlay_default_hide(overlay->ovl);
+     }
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_GROUP)
+     {
+        if (overlay->visible) _overlay_group_show(overlay->ovl);
+        else _overlay_group_hide(overlay->ovl);
      }
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_BUBBLE)
      {
-        if (hide) _overlay_bubble_hide(overlay->ovl);
-        else _overlay_bubble_show(overlay->ovl);
+        overlay->visible = _overlay_bubble_show_hide(overlay->ovl,
+                                                     overlay->visible);
      }
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_ROUTE)
      {
-       if (hide) _overlay_route_hide(overlay->ovl);
-       else _overlay_route_show(overlay->ovl);
+       if (overlay->visible) _overlay_route_show(overlay->ovl);
+       else _overlay_route_hide(overlay->ovl);
+     }
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_LINE)
+     {
+        if (overlay->visible) _overlay_line_show(overlay->ovl);
+        else _overlay_line_hide(overlay->ovl);
+     }
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_POLYGON)
+     {
+        if (overlay->visible) _overlay_polygon_show(overlay->ovl);
+        else _overlay_polygon_hide(overlay->ovl);
+     }
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_CIRCLE)
+     {
+        if (overlay->visible) _overlay_circle_show(overlay->ovl);
+        else _overlay_circle_hide(overlay->ovl);
+     }
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_SCALE)
+     {
+        if (overlay->visible) _overlay_scale_show(overlay->ovl);
+        else _overlay_scale_hide(overlay->ovl);
      }
 }
 
@@ -2604,13 +2429,19 @@ _overlay_place(Widget_Data *wd)
    Eina_List *l, *ll;
    Elm_Map_Overlay *overlay;
 
-   // Reset group & Update overlays coord
+   eina_list_free(wd->group_overlays);
+   wd->group_overlays = NULL;
+
    EINA_LIST_FOREACH(wd->overlays, l, overlay)
      {
-        if (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS) continue;
+        // Reset groups
+        if ((overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS) ||
+            (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS)) continue;
         overlay->grp->in = EINA_FALSE;
         overlay->grp->boss = EINA_FALSE;
+        _overlay_group_hide(overlay->grp);
 
+        // Update overlays' coord
         if (overlay->type == ELM_MAP_OVERLAY_TYPE_DEFAULT)
            _overlay_default_coord_update(overlay->ovl);
         else if (overlay->type == ELM_MAP_OVERLAY_TYPE_BUBBLE)
@@ -2637,16 +2468,9 @@ _overlay_place(Widget_Data *wd)
           }
      }
 
-   // Place overlays
+   // Place group overlays and overlays
+   EINA_LIST_FOREACH(wd->group_overlays, l, overlay) _overlay_show(overlay);
    EINA_LIST_FOREACH(wd->overlays, l, overlay)  _overlay_show(overlay);
-
-   // Place group overlays on top of overlays
-   EINA_LIST_FOREACH(wd->overlays, l, overlay)
-     {
-        if (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS) continue;
-        if (overlay->grp->boss) _overlay_group_show(overlay->grp);
-        else _overlay_group_hide(overlay->grp);
-     }
 }
 
 static Evas_Object *
@@ -2677,7 +2501,7 @@ _overlays_show(void *data)
    EINA_SAFETY_ON_NULL_RETURN(data);
    Delayed_Data *dd = data;
 
-   int zoom;
+   int zoom, zoom_max;
    double max_lon, min_lon, max_lat, min_lat;
    Evas_Coord vw, vh;
 
@@ -2687,7 +2511,10 @@ _overlays_show(void *data)
 
    zoom = dd->wd->src_tile->zoom_min;
    _viewport_coord_get(dd->wd, NULL, NULL, &vw, &vh);
-   while (zoom <= dd->wd->src_tile->zoom_max)
+   if (dd->wd->src_tile->zoom_max < dd->wd->zoom_max)
+      zoom_max = dd->wd->src_tile->zoom_max;
+   else zoom_max = dd->wd->zoom_max;
+   while (zoom <= zoom_max)
      {
         Evas_Coord size, max_x, max_y, min_x, min_y;
         size = pow(2.0, zoom) * dd->wd->tsize;
@@ -2791,7 +2618,6 @@ _pan_calculate(Evas_Object *obj)
    if (w <= 0 || h <= 0) return;
 
    _grid_place(sd->wd);
-   _marker_place(sd->wd);
    _overlay_place(sd->wd);
    _track_place(sd->wd);
    _delayed_do(sd->wd);
@@ -2836,33 +2662,6 @@ _freeze_off(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__
    elm_smart_scroller_freeze_set(wd->scr, 0);
 }
 
-static void
-_elm_map_marker_remove(Elm_Map_Marker *marker)
-{
-#ifdef HAVE_ELEMENTARY_ECORE_CON
-   EINA_SAFETY_ON_NULL_RETURN(marker);
-   Widget_Data *wd = marker->wd;
-   EINA_SAFETY_ON_NULL_RETURN(wd);
-
-   if ((marker->content) && (marker->clas->func.del))
-      marker->clas->func.del(wd->obj, marker, marker->data, marker->content);
-
-   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);
-
-   evas_object_smart_changed(wd->pan_smart);
-#else
-   (void) marker;
-#endif
-}
-
 static Eina_Bool
 cb_dump_name_attrs(void *data, const char *key, const char *value)
 {
@@ -3291,6 +3090,7 @@ _source_tile_mod_cb(Eina_Module *m, void *data)
    Elm_Map_Module_Tile_Url_Func url_cb;
    Elm_Map_Module_Tile_Geo_to_Coord_Func geo_to_coord;
    Elm_Map_Module_Tile_Coord_to_Geo_Func coord_to_geo;
+   Elm_Map_Module_Tile_Scale_Func scale_cb;
    const char *file;
 
    file = eina_module_file_get(m);
@@ -3307,9 +3107,9 @@ _source_tile_mod_cb(Eina_Module *m, void *data)
    url_cb = eina_module_symbol_get(m, "map_module_tile_url_get");
    geo_to_coord = eina_module_symbol_get(m, "map_module_tile_geo_to_coord");
    coord_to_geo = eina_module_symbol_get(m, "map_module_tile_coord_to_geo");
-
+   scale_cb = eina_module_symbol_get(m, "map_module_tile_scale_get");
    if ((!name_cb) || (!zoom_min) || (!zoom_max) || (!url_cb) ||
-       (!geo_to_coord) || (!coord_to_geo))
+       (!geo_to_coord) || (!coord_to_geo) || (!scale_cb))
      {
         WRN("Could not find map module functions from module \"%s\": %s",
             file, eina_error_msg_get(eina_error_get()));
@@ -3323,6 +3123,7 @@ _source_tile_mod_cb(Eina_Module *m, void *data)
    s->url_cb = url_cb;
    s->geo_to_coord = geo_to_coord;
    s->coord_to_geo = coord_to_geo;
+   s->scale_cb = scale_cb;
    wd->src_tiles = eina_list_append(wd->src_tiles, s);
 
    return EINA_TRUE;
@@ -3345,6 +3146,7 @@ _source_tile_load(Widget_Data *wd)
         s->url_cb = src_tiles[idx].url_cb;
         s->geo_to_coord = src_tiles[idx].geo_to_coord;
         s->coord_to_geo = src_tiles[idx].coord_to_geo;
+        s->scale_cb = src_tiles[idx].scale_cb;
         wd->src_tiles = eina_list_append(wd->src_tiles, s);
      }
 
@@ -3724,7 +3526,7 @@ _zoom_mode_set(void *data)
                   }
                }
           }
-       zoom_with_animation(dd->wd, zoom, 10);
+        zoom_do(dd->wd, zoom);
      }
 }
 
@@ -3880,6 +3682,13 @@ _nominatim_url_cb(const Evas_Object *obj, int method, const char *name, double l
    return strdup(buf);
 }
 
+static double
+_scale_cb(const Evas_Object *obj __UNUSED__, double lon __UNUSED__, double lat, int zoom)
+{
+   if (zoom < 0 || zoom >= (int)sizeof(_osm_scale_meter)) return 0;
+   return _osm_scale_meter[zoom] / cos(lat * ELM_PI / 180.0);
+}
+
 static void
 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
 {
@@ -3921,9 +3730,6 @@ _del_pre_hook(Evas_Object *obj)
    Elm_Map_Route *r;
    Elm_Map_Name *na;
    Evas_Object *track;
-   Elm_Map_Marker *marker;
-   Elm_Map_Group_Class *group_clas;
-   Elm_Map_Marker_Class *clas;
    Elm_Map_Overlay *overlay;
    Delayed_Data *dd;
 
@@ -3936,25 +3742,11 @@ _del_pre_hook(Evas_Object *obj)
    EINA_LIST_FOREACH_SAFE(wd->overlays, l, ll, overlay)
       elm_map_overlay_del(overlay);
    eina_list_free(wd->overlays);
+   eina_list_free(wd->group_overlays);
+   eina_list_free(wd->all_overlays);
 
    EINA_LIST_FREE(wd->track, track) evas_object_del(track);
 
-   EINA_LIST_FOREACH_SAFE(wd->markers, l, ll, marker)
-      _elm_map_marker_remove(marker);
-   eina_list_free(wd->markers);
-
-   EINA_LIST_FREE(wd->group_classes, group_clas)
-     {
-        eina_list_free(group_clas->markers);
-        if (group_clas->style) eina_stringshare_del(group_clas->style);
-        free(group_clas);
-     }
-   EINA_LIST_FREE(wd->marker_classes, clas)
-     {
-        if (clas->style) eina_stringshare_del(clas->style);
-        free(clas);
-     }
-
    if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
    if (wd->long_timer) ecore_timer_del(wd->long_timer);
 
@@ -4008,30 +3800,36 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
    elm_smart_scroller_child_viewport_size_get(wd->scr, NULL, &vh);
 
-   if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
+   if ((!strcmp(ev->keyname, "Left")) ||
+       ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
      {
         x -= step_x;
      }
-   else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
+   else if ((!strcmp(ev->keyname, "Right")) ||
+            ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
      {
         x += step_x;
      }
-   else if ((!strcmp(ev->keyname, "Up"))  || (!strcmp(ev->keyname, "KP_Up")))
+   else if ((!strcmp(ev->keyname, "Up")) ||
+            ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string)))
      {
         y -= step_y;
      }
-   else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
+   else if ((!strcmp(ev->keyname, "Down")) ||
+            ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string)))
      {
         y += step_y;
      }
-   else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior")))
+   else if ((!strcmp(ev->keyname, "Prior")) ||
+            ((!strcmp(ev->keyname, "KP_Prior")) && (!ev->string)))
      {
         if (page_y < 0)
           y -= -(page_y * vh) / 100;
         else
           y -= page_y;
      }
-   else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
+   else if ((!strcmp(ev->keyname, "Next")) ||
+            ((!strcmp(ev->keyname, "KP_Next")) && (!ev->string)))
      {
         if (page_y < 0)
           y += -(page_y * vh) / 100;
@@ -4086,7 +3884,7 @@ elm_map_add(Evas_Object *parent)
    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);
+                                  _mouse_wheel_cb, wd);
    wd->obj = obj;
 
    wd->scr = elm_smart_scroller_add(e);
@@ -4147,9 +3945,9 @@ elm_map_add(Evas_Object *parent)
    elm_gesture_layer_cb_set(wd->ges, ELM_GESTURE_ROTATE, ELM_GESTURE_STATE_ABORT,
                             _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);
+   wd->sep_maps_overlays = evas_object_rectangle_add(evas_object_evas_get(obj));
+   elm_widget_sub_object_add(obj, wd->sep_maps_overlays);
+   evas_object_smart_member_add(wd->sep_maps_overlays, wd->pan_smart);
 
    wd->map = evas_map_new(EVAS_MAP_POINT);
 
@@ -4168,7 +3966,6 @@ elm_map_add(Evas_Object *parent)
    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!
@@ -4196,9 +3993,6 @@ elm_map_zoom_set(Evas_Object *obj, int zoom)
    if (wd->mode != ELM_MAP_ZOOM_MODE_MANUAL) return;
    if (zoom < 0) zoom = 0;
    if (wd->zoom == zoom) return;
-   if (zoom > wd->src_tile->zoom_max) zoom = wd->src_tile->zoom_max;
-   if (zoom < wd->src_tile->zoom_min) zoom = wd->src_tile->zoom_min;
-
    Delayed_Data *data = ELM_NEW(Delayed_Data);
    data->func = _zoom_set;
    data->wd = wd;
@@ -4272,8 +4066,6 @@ elm_map_zoom_max_set(Evas_Object *obj, int zoom)
    EINA_SAFETY_ON_NULL_RETURN(wd);
    EINA_SAFETY_ON_NULL_RETURN(wd->src_tile);
 
-   if ((zoom > wd->src_tile->zoom_max) || (zoom < wd->src_tile->zoom_min))
-      return;
    wd->zoom_max = zoom;
 #else
    (void) obj;
@@ -4285,7 +4077,7 @@ EAPI int
 elm_map_zoom_max_get(const Evas_Object *obj)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
-   ELM_CHECK_WIDTYPE(obj, widtype) 18;
+   ELM_CHECK_WIDTYPE(obj, widtype) -1;
    Widget_Data *wd = elm_widget_data_get(obj);
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, -1);
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src_tile, -1);
@@ -4293,7 +4085,7 @@ elm_map_zoom_max_get(const Evas_Object *obj)
    return wd->zoom_max;
 #else
    (void) obj;
-   return 18;
+   return -1;
 #endif
 }
 
@@ -4306,8 +4098,6 @@ elm_map_zoom_min_set(Evas_Object *obj, int zoom)
    EINA_SAFETY_ON_NULL_RETURN(wd);
    EINA_SAFETY_ON_NULL_RETURN(wd->src_tile);
 
-   if ((zoom > wd->src_tile->zoom_max) || (zoom < wd->src_tile->zoom_min))
-      return;
    wd->zoom_min = zoom;
 #else
    (void) obj;
@@ -4319,7 +4109,7 @@ EAPI int
 elm_map_zoom_min_get(const Evas_Object *obj)
 {
 #ifdef HAVE_ELEMENTARY_ECORE_CON
-   ELM_CHECK_WIDTYPE(obj, widtype) 0;
+   ELM_CHECK_WIDTYPE(obj, widtype) -1;
    Widget_Data *wd = elm_widget_data_get(obj);
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, -1);
    EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src_tile, -1);
@@ -4327,11 +4117,10 @@ elm_map_zoom_min_get(const Evas_Object *obj)
    return wd->zoom_min;
 #else
    (void) obj;
-   return 0;
+   return -1;
 #endif
 }
 
-
 EAPI void
 elm_map_region_bring_in(Evas_Object *obj, double lon, double lat)
 {
@@ -4493,9 +4282,9 @@ elm_map_wheel_disabled_set(Evas_Object *obj, Eina_Bool disabled)
    EINA_SAFETY_ON_NULL_RETURN(wd);
 
    if ((!wd->wheel_disabled) && (disabled))
-     evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
+     evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, wd);
    else if ((wd->wheel_disabled) && (!disabled))
-     evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, obj);
+     evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, wd);
    wd->wheel_disabled = !!disabled;
 #else
    (void) obj;
@@ -4929,6 +4718,32 @@ elm_map_overlay_add(Evas_Object *obj, double lon, double lat)
 #endif
 }
 
+EAPI Eina_List *
+elm_map_overlays_get(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);
+
+   Eina_List *l;
+   Elm_Map_Overlay *ovl;
+
+   eina_list_free(wd->all_overlays);
+   wd->all_overlays = NULL;
+
+   EINA_LIST_FOREACH(wd->overlays, l, ovl)
+      wd->all_overlays = eina_list_append(wd->all_overlays, ovl);
+   EINA_LIST_FOREACH(wd->group_overlays, l, ovl)
+      wd->all_overlays = eina_list_append(wd->all_overlays, ovl);
+
+   return wd->all_overlays;
+#else
+   (void) obj;
+   return NULL;
+#endif
+}
+
 EAPI void
 elm_map_overlay_del(Elm_Map_Overlay *overlay)
 {
@@ -4952,6 +4767,14 @@ elm_map_overlay_del(Elm_Map_Overlay *overlay)
       _overlay_class_free(overlay->ovl);
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_ROUTE)
       _overlay_route_free(overlay->ovl);
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_LINE)
+      _overlay_line_free(overlay->ovl);
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_POLYGON)
+      _overlay_polygon_free(overlay->ovl);
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_CIRCLE)
+      _overlay_circle_free(overlay->ovl);
+   else if (overlay->type == ELM_MAP_OVERLAY_TYPE_SCALE)
+      _overlay_scale_free(overlay->ovl);
    else ERR("Invalid overlay type: %d", overlay->type);
 
    overlay->wd->overlays = eina_list_remove(overlay->wd->overlays, overlay);
@@ -5105,6 +4928,21 @@ elm_map_overlay_paused_get(const Elm_Map_Overlay *overlay)
 #endif
 }
 
+EAPI Eina_Bool
+elm_map_overlay_visible_get(const Elm_Map_Overlay *overlay)
+{
+#ifdef HAVE_ELEMENTARY_ECORE_CON
+   EINA_SAFETY_ON_NULL_RETURN_VAL(overlay, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(overlay->wd, EINA_FALSE);
+   ELM_CHECK_WIDTYPE(overlay->wd->obj, widtype) EINA_FALSE;
+
+   return overlay->visible;
+#else
+   (void) overlay;
+   return EINA_FALSE;
+#endif
+}
+
 EAPI void
 elm_map_overlay_show(Elm_Map_Overlay *overlay)
 {
@@ -5178,6 +5016,7 @@ elm_map_overlay_region_set(Elm_Map_Overlay *overlay, double lon, double lat)
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_BUBBLE)
      {
         Overlay_Bubble *ovl = overlay->ovl;
+        ovl->pobj = NULL;
         ovl->lon = lon;
         ovl->lat = lat;
      }
@@ -5202,7 +5041,8 @@ elm_map_overlay_region_get(const Elm_Map_Overlay *overlay, double *lon, double *
    if (overlay->type == ELM_MAP_OVERLAY_TYPE_GROUP)
      {
         Overlay_Group *ovl = overlay->ovl;
-        _overlay_group_region_get(ovl, lon, lat);
+        if (lon) *lon = ovl->lon;
+        if (lat) *lat = ovl->lat;
      }
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_DEFAULT)
      {
@@ -5308,12 +5148,12 @@ elm_map_overlay_content_get(const Elm_Map_Overlay *overlay)
    if (overlay->type == ELM_MAP_OVERLAY_TYPE_DEFAULT)
      {
         const Overlay_Default *ovl = overlay->ovl;
-        return elm_object_part_content_get(ovl->layout, "elm.icon");
+        return ovl->content;
      }
    else if (overlay->type == ELM_MAP_OVERLAY_TYPE_CLASS)
      {
         const Overlay_Class *ovl = overlay->ovl;
-        return ovl->icon;
+        return ovl->content;
      }
    else
      {
@@ -5533,6 +5373,23 @@ elm_map_overlay_class_zoom_max_get(const Elm_Map_Overlay *clas)
 #endif
 }
 
+EAPI Eina_List *
+elm_map_overlay_group_members_get(const Elm_Map_Overlay *grp)
+{
+#ifdef HAVE_ELEMENTARY_ECORE_CON
+   EINA_SAFETY_ON_NULL_RETURN_VAL(grp, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(grp->wd, NULL);
+   ELM_CHECK_WIDTYPE(grp->wd->obj, widtype) NULL;
+  EINA_SAFETY_ON_FALSE_RETURN_VAL(grp->type == ELM_MAP_OVERLAY_TYPE_GROUP, NULL);
+
+   Overlay_Group *ovl = grp->ovl;
+   return ovl->members;
+#else
+   (void) clas;
+   return OVERLAY_CLASS_ZOOM_MAX;
+#endif
+}
+
 EAPI Elm_Map_Overlay *
 elm_map_overlay_bubble_add(Evas_Object *obj)
 {
@@ -5573,25 +5430,7 @@ elm_map_overlay_bubble_follow(Elm_Map_Overlay *bubble, const Elm_Map_Overlay *pa
    Evas_Object *pobj = _overlay_obj_get(parent);
    if (!pobj) return;
 
-   if (ovl->pobj)
-     {
-        evas_object_event_callback_del_full(ovl->pobj, EVAS_CALLBACK_HIDE,
-                                            _overlay_bubble_hide_cb, ovl);
-        evas_object_event_callback_del_full(ovl->pobj, EVAS_CALLBACK_SHOW,
-                                            _overlay_bubble_chase_cb, ovl);
-        evas_object_event_callback_del_full(ovl->pobj, EVAS_CALLBACK_MOVE,
-                                            _overlay_bubble_chase_cb, ovl);
-     }
-
    ovl->pobj = pobj;
-   evas_object_event_callback_add(ovl->pobj, EVAS_CALLBACK_HIDE,
-                                  _overlay_bubble_hide_cb, ovl);
-   evas_object_event_callback_add(ovl->pobj, EVAS_CALLBACK_SHOW,
-                                  _overlay_bubble_chase_cb, ovl);
-   evas_object_event_callback_add(ovl->pobj, EVAS_CALLBACK_MOVE,
-                                  _overlay_bubble_chase_cb, ovl);
-
-   _overlay_bubble_chase(ovl);
    evas_object_smart_changed(bubble->wd->pan_smart);
 #else
    (void) bubble;
@@ -5666,6 +5505,139 @@ elm_map_overlay_route_add(Evas_Object *obj, const Elm_Map_Route *route)
 #endif
 }
 
+EAPI Elm_Map_Overlay *
+elm_map_overlay_line_add(Evas_Object *obj, double flon, double flat, double tlon, double tlat)
+{
+#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_Overlay *overlay = ELM_NEW(Elm_Map_Overlay);
+   overlay->wd = wd;
+   overlay->type = ELM_MAP_OVERLAY_TYPE_LINE;
+   overlay->c.r = 0xff;
+   overlay->c.g = 0x00;
+   overlay->c.b = 0x00;
+   overlay->c.a = 0xff;
+   overlay->ovl =  _overlay_line_new(wd, flon, flat, tlon, tlat, overlay->c);
+   overlay->grp = _overlay_group_new(wd);
+   wd->overlays = eina_list_append(wd->overlays, overlay);
+
+   evas_object_smart_changed(wd->pan_smart);
+   return overlay;
+#else
+   (void) obj;
+   (void) flon;
+   (void) flat
+   (void) tlon;
+   (void) tlat;
+   return NULL;
+#endif
+}
+
+EAPI Elm_Map_Overlay *
+elm_map_overlay_polygon_add(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_Overlay *overlay = ELM_NEW(Elm_Map_Overlay);
+   overlay->wd = wd;
+   overlay->type = ELM_MAP_OVERLAY_TYPE_POLYGON;
+   overlay->c.r = 0xdc;
+   overlay->c.g = 0x14;
+   overlay->c.b = 0x3c;
+   overlay->c.a = 200;
+   overlay->ovl =  _overlay_polygon_new(wd, overlay->c);
+   overlay->grp = _overlay_group_new(wd);
+   wd->overlays = eina_list_append(wd->overlays, overlay);
+   evas_object_smart_changed(wd->pan_smart);
+   return overlay;
+#else
+   (void) obj;
+    return NULL;
+#endif
+}
+
+EAPI void
+elm_map_overlay_polygon_region_add(Elm_Map_Overlay *overlay, double lon, double lat)
+{
+#ifdef HAVE_ELEMENTARY_ECORE_CON
+   EINA_SAFETY_ON_NULL_RETURN(overlay);
+   ELM_CHECK_WIDTYPE(overlay->wd->obj, widtype);
+   EINA_SAFETY_ON_FALSE_RETURN(overlay->type == ELM_MAP_OVERLAY_TYPE_POLYGON);
+
+   Overlay_Polygon *ovl = overlay->ovl;
+   Region *r = ELM_NEW(Region);
+   r->lon = lon;
+   r->lat = lat;
+   ovl->regions = eina_list_append(ovl->regions, r);
+
+   evas_object_smart_changed(ovl->wd->pan_smart);
+#else
+   (void) overlay;
+   (void) lon;
+   (void) lat
+ #endif
+}
+
+EAPI Elm_Map_Overlay *
+elm_map_overlay_circle_add(Evas_Object *obj, double lon, double lat, double radius)
+{
+#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_Overlay *overlay = ELM_NEW(Elm_Map_Overlay);
+   overlay->wd = wd;
+   overlay->type = ELM_MAP_OVERLAY_TYPE_CIRCLE;
+   overlay->c.r = 0xdc;
+   overlay->c.g = 0x14;
+   overlay->c.b = 0x3c;
+   overlay->c.a = 200;
+   overlay->ovl = _overlay_circle_new(wd, lon, lat, radius, overlay->c);
+   overlay->grp = _overlay_group_new(wd);
+   wd->overlays = eina_list_append(wd->overlays, overlay);
+
+   evas_object_smart_changed(wd->pan_smart);
+   return overlay;
+#else
+   (void) obj;
+    return NULL;
+#endif
+}
+
+EAPI Elm_Map_Overlay *
+elm_map_overlay_scale_add(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+#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_Overlay *overlay = ELM_NEW(Elm_Map_Overlay);
+   overlay->wd = wd;
+   overlay->type = ELM_MAP_OVERLAY_TYPE_SCALE;
+   overlay->c.r = 0;
+   overlay->c.g = 0;
+   overlay->c.b = 0;
+   overlay->c.a = 255;
+   overlay->ovl = _overlay_scale_new(wd, x, y, overlay->c);
+   overlay->grp = _overlay_group_new(wd);
+   wd->overlays = eina_list_append(wd->overlays, overlay);
+
+   evas_object_smart_changed(wd->pan_smart);
+   return overlay;
+#else
+   (void) obj;
+    return NULL;
+#endif
+}
+
 #ifdef ELM_EMAP
 EAPI Evas_Object *
 elm_map_track_add(Evas_Object *obj, void *emap)