+Grid *_get_current_grid(Widget_Data *wd)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+ Eina_List *l;
+ Grid *g = NULL, *ret = NULL;
+ EINA_LIST_FOREACH(wd->grids, l, g)
+ {
+ if (wd->zoom == g->zoom)
+ {
+ ret = g;
+ break;
+ }
+ }
+ return ret;
+}
+
+static void
+_route_cb(void *data, const char *file, int status)
+{
+ EINA_SAFETY_ON_NULL_RETURN(data);
+ EINA_SAFETY_ON_NULL_RETURN(file);
+
+ Elm_Map_Route *route = data;
+ Widget_Data *wd = route->wd;
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ route->job = NULL;
+ if (status == 200)
+ {
+ _kml_parse(route);
+ INF("Route request success from (%lf, %lf) to (%lf, %lf)",
+ route->flon, route->flat, route->tlon, route->tlat);
+ if (route->cb) route->cb(route->data, wd->obj, route);
+ evas_object_smart_callback_call(wd->obj, SIG_ROUTE_LOADED, NULL);
+ }
+ else
+ {
+ ERR("Route request failed: %d", status);
+ if (route->cb) route->cb(route->data, wd->obj, NULL);
+ evas_object_smart_callback_call(wd->obj, SIG_ROUTE_LOADED_FAIL, NULL);
+ }
+
+ edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
+ "elm,state,busy,stop", "elm");
+}
+
+static void
+_name_cb(void *data, const char *file, int status)
+{
+ EINA_SAFETY_ON_NULL_RETURN(data);
+ EINA_SAFETY_ON_NULL_RETURN(file);
+
+ Elm_Map_Name *name = data;
+ Widget_Data *wd = name->wd;
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ name->job = NULL;
+ if (status == 200)
+ {
+ _name_parse(name);
+ INF("Name request success address:%s, lon:%lf, lat:%lf",
+ name->address, name->lon, name->lat);
+ if (name->cb) name->cb(name->data, wd->obj, name);
+ evas_object_smart_callback_call(wd->obj, SIG_NAME_LOADED, NULL);
+ }
+ else
+ {
+ ERR("Name request failed: %d", status);
+ if (name->cb) name->cb(name->data, wd->obj, NULL);
+ evas_object_smart_callback_call(wd->obj, SIG_NAME_LOADED_FAIL, NULL);
+ }
+ edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
+ "elm,state,busy,stop", "elm");
+}
+
+
+
+static Elm_Map_Name *
+_name_request(const Evas_Object *obj, int method, const char *address, double lon, double lat, Elm_Map_Name_Cb name_cb, void *data)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype) NULL;
+ Widget_Data *wd = elm_widget_data_get(obj);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wd->src_name, NULL);
+
+
+ char *url;
+ char fname[PATH_MAX];
+
+ if (!ecore_file_exists(CACHE_NAME_ROOT)) ecore_file_mkpath(CACHE_NAME_ROOT);
+
+ url = wd->src_name->url_cb(wd->obj, method, address, lon, lat);
+ if (!url)
+ {
+ ERR("Name URL is NULL");
+ return NULL;
+ }
+
+ Elm_Map_Name *name = ELM_NEW(Elm_Map_Name);
+ name->wd = wd;
+ snprintf(fname, sizeof(fname), CACHE_NAME_ROOT"/%d", rand());
+ name->fname = strdup(fname);
+ name->method = method;
+ if (method == ELM_MAP_NAME_METHOD_SEARCH) name->address = strdup(address);
+ else if (method == ELM_MAP_NAME_METHOD_REVERSE)
+ {
+ name->lon = lon;
+ name->lat = lat;
+ }
+ name->cb = name_cb;
+ name->data = data;
+
+ if (!ecore_file_download_full(url, name->fname, _name_cb, NULL, name,
+ &(name->job), wd->ua) || !(name->job))
+ {
+ ERR("Can't request Name from %s to %s", url, name->fname);
+ if (name->address) free(name->address);
+ free(name->fname);
+ free(name);
+ return NULL;
+ }
+ INF("Name requested from %s to %s", url, name->fname);
+ free(url);
+
+ wd->names = eina_list_append(wd->names, name);
+ evas_object_smart_callback_call(wd->obj, SIG_NAME_LOAD, name);
+ edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
+ "elm,state,busy,start", "elm");
+ return name;
+}
+
+static Evas_Event_Flags
+_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);
+
+ 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->rotate.d = wd->rotate.a + ei->angle - ei->base_angle;
+ 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
+_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);
+
+ wd->rotate.a = wd->rotate.d;
+
+ return EVAS_EVENT_FLAG_NONE;
+}
+
+static Eina_Bool
+_source_tile_mod_cb(Eina_Module *m, void *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+
+ Widget_Data *wd = data;
+ Source_Tile *s;
+ Elm_Map_Module_Source_Name_Func name_cb;
+ Elm_Map_Module_Tile_Zoom_Min_Func zoom_min;
+ Elm_Map_Module_Tile_Zoom_Max_Func zoom_max;
+ 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);
+ if (!eina_module_load(m))
+ {
+ ERR("Could not load module \"%s\": %s", file,
+ eina_error_msg_get(eina_error_get()));
+ return EINA_FALSE;
+ }
+
+ name_cb = eina_module_symbol_get(m, "map_module_source_name_get");
+ zoom_min = eina_module_symbol_get(m, "map_module_tile_zoom_min_get");
+ zoom_max = eina_module_symbol_get(m, "map_module_tile_zoom_max_get");
+ 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) || (!scale_cb))
+ {
+ WRN("Could not find map module functions from module \"%s\": %s",
+ file, eina_error_msg_get(eina_error_get()));
+ eina_module_unload(m);
+ return EINA_FALSE;
+ }
+ s = ELM_NEW(Source_Tile);
+ s->name = name_cb();
+ s->zoom_min = zoom_min();
+ s->zoom_max = zoom_max();
+ 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;
+}
+
+static void
+_source_tile_load(Widget_Data *wd)
+{
+ unsigned int idx;
+ Eina_List *l;
+ Source_Tile *s;
+
+ // Load from hard coded data
+ for (idx = 0; idx < (sizeof(src_tiles) / sizeof(Source_Tile)); idx++)
+ {
+ s= ELM_NEW(Source_Tile);
+ s->name = src_tiles[idx].name;
+ s->zoom_min = src_tiles[idx].zoom_min;
+ s->zoom_max = src_tiles[idx].zoom_max;
+ 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);
+ }
+
+ // Load from modules
+ wd->src_tile_mods = eina_module_list_get(wd->src_tile_mods, MODULES_PATH, 1,
+ &_source_tile_mod_cb, wd);
+
+ // Set default source
+ wd->src_tile = eina_list_nth(wd->src_tiles, 0);
+
+ // Make name strings
+ idx = 0;
+ wd->src_tile_names = calloc((eina_list_count(wd->src_tiles) + 1),
+ sizeof(char *));
+ EINA_LIST_FOREACH(wd->src_tiles, l, s)
+ {
+ eina_stringshare_replace(&wd->src_tile_names[idx], s->name);
+ INF("source : %s", wd->src_tile_names[idx]);
+ idx++;
+ }
+}
+
+static void
+_source_tile_unload(Widget_Data *wd)
+{
+ int idx = 0;
+ Source_Tile *s;
+
+ for (idx = 0; wd->src_tile_names[idx]; idx++)
+ eina_stringshare_del(wd->src_tile_names[idx]);
+ EINA_LIST_FREE(wd->src_tiles, s) free(s);
+ eina_module_list_free(wd->src_tile_mods);
+}
+
+static void
+_source_tile_set(Widget_Data *wd, const char *source_name)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ EINA_SAFETY_ON_NULL_RETURN(source_name);
+ Source_Tile *s;
+ Eina_List *l;
+
+ if (wd->src_tile && !strcmp(wd->src_tile->name, source_name)) return;
+
+ EINA_LIST_FOREACH(wd->src_tiles, l, s)
+ {
+ if (!strcmp(s->name, source_name))
+ {
+ wd->src_tile = s;
+ break;
+ }
+ }
+ if (!wd->src_tile)
+ {
+ ERR("source name (%s) is not found", source_name);
+ return;
+ }
+
+ if (wd->src_tile->zoom_max < wd->zoom)
+ wd->zoom = wd->src_tile->zoom_max;
+ else if (wd->src_tile->zoom_min > wd->zoom)
+ wd->zoom = wd->src_tile->zoom_min;
+
+ if (wd->src_tile->zoom_max < wd->zoom_max)
+ wd->zoom_max = wd->src_tile->zoom_max;
+ if (wd->src_tile->zoom_min > wd->zoom_min)
+ wd->zoom_min = wd->src_tile->zoom_min;
+
+ _grid_all_clear(wd);
+ _grid_all_create(wd);
+ zoom_do(wd, wd->zoom);
+}
+
+static Eina_Bool
+_source_route_mod_cb(Eina_Module *m, void *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+
+ Widget_Data *wd = data;
+ Source_Route *s;
+ Elm_Map_Module_Source_Name_Func name_cb;
+ Elm_Map_Module_Route_Url_Func url_cb;
+ const char *file;
+
+ 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()));
+ return EINA_FALSE;
+ }
+
+ name_cb = eina_module_symbol_get(m, "map_module_source_name_get");
+ url_cb = eina_module_symbol_get(m, "map_module_route_url_get");
+
+ if ((!name_cb) || (!url_cb))
+ {
+ WRN("Could not find map module functions from module \"%s\": %s",
+ file, eina_error_msg_get(eina_error_get()));
+ eina_module_unload(m);
+ return EINA_FALSE;
+ }
+ s = ELM_NEW(Source_Tile);
+ s->name = name_cb();
+ s->url_cb = url_cb;
+ wd->src_routes = eina_list_append(wd->src_routes, s);
+
+ eina_module_unload(m);
+ return EINA_TRUE;
+}
+
+static void
+_source_route_load(Widget_Data *wd)
+{
+ unsigned int idx;
+ Eina_List *l;
+ Source_Route *s;
+
+ // Load from hard coded data
+ for (idx = 0; idx < (sizeof(src_routes) / sizeof(Source_Route)); idx++)
+ {
+ s= ELM_NEW(Source_Route);
+ s->name = src_routes[idx].name;
+ s->url_cb = src_routes[idx].url_cb;
+ wd->src_routes = eina_list_append(wd->src_routes, s);
+ }
+
+ // Load from modules
+ wd->src_route_mods = eina_module_list_get(wd->src_route_mods, MODULES_PATH,
+ 1, &_source_route_mod_cb, wd);
+
+ // Set default source
+ wd->src_route = eina_list_nth(wd->src_routes, 0);
+
+ // Make name strings
+ idx = 0;
+ wd->src_route_names = calloc((eina_list_count(wd->src_routes) + 1),
+ sizeof(char *));
+ EINA_LIST_FOREACH(wd->src_routes, l, s)
+ {
+ eina_stringshare_replace(&wd->src_route_names[idx], s->name);
+ INF("source : %s", wd->src_route_names[idx]);
+ idx++;
+ }
+}
+
+static void
+_source_route_unload(Widget_Data *wd)
+{
+ int idx = 0;
+ Source_Route *s;
+
+ for (idx = 0; wd->src_route_names[idx]; idx++)
+ eina_stringshare_del(wd->src_route_names[idx]);
+ EINA_LIST_FREE(wd->src_routes, s) free(s);
+ eina_module_list_free(wd->src_route_mods);
+}
+
+static void
+_source_route_set(Widget_Data *wd, const char *source_name)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ EINA_SAFETY_ON_NULL_RETURN(source_name);
+ Source_Route *s;
+ Eina_List *l;
+
+ if (wd->src_route && !strcmp(wd->src_route->name, source_name)) return;
+
+ EINA_LIST_FOREACH(wd->src_routes, l, s)
+ {
+ if (!strcmp(s->name, source_name))
+ {
+ wd->src_route = s;
+ break;
+ }
+ }
+ if (!wd->src_route)
+ {
+ ERR("source name (%s) is not found", source_name);
+ return;
+ }
+}
+
+static Eina_Bool
+_source_name_mod_cb(Eina_Module *m, void *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+
+ Widget_Data *wd = data;
+ Source_Name *s;
+ Elm_Map_Module_Source_Name_Func name_cb;
+ Elm_Map_Module_Name_Url_Func url_cb;
+ const char *file;
+
+ 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()));
+ return EINA_FALSE;
+ }
+
+ name_cb = eina_module_symbol_get(m, "map_module_source_name_get");
+ url_cb = eina_module_symbol_get(m, "map_module_name_url_get");
+
+ if ((!name_cb) || (!url_cb))
+ {
+ WRN("Could not find map module functions from module \"%s\": %s",
+ file, eina_error_msg_get(eina_error_get()));
+ eina_module_unload(m);
+ return EINA_FALSE;
+ }
+ s = ELM_NEW(Source_Tile);
+ s->name = name_cb();
+ s->url_cb = url_cb;
+ wd->src_names = eina_list_append(wd->src_names, s);
+
+ eina_module_unload(m);
+ return EINA_TRUE;
+}
+
+static void
+_source_name_load(Widget_Data *wd)
+{
+ unsigned int idx;
+ Eina_List *l;
+ Source_Name *s;
+
+ // Load from hard coded data
+ for (idx = 0; idx < (sizeof(src_names) / sizeof(Source_Name)); idx++)
+ {
+ s= ELM_NEW(Source_Name);
+ s->name = src_names[idx].name;
+ s->url_cb = src_names[idx].url_cb;
+ wd->src_names = eina_list_append(wd->src_names, s);
+ }
+
+ // Load from modules
+ wd->src_name_mods = eina_module_list_get(wd->src_name_mods, MODULES_PATH, 1,
+ &_source_name_mod_cb, wd);
+
+ // Set default source
+ wd->src_name = eina_list_nth(wd->src_names, 0);
+
+ // Make name strings
+ idx = 0;
+ wd->src_name_names = calloc((eina_list_count(wd->src_names) + 1),
+ sizeof(char *));
+ EINA_LIST_FOREACH(wd->src_names, l, s)
+ {
+ eina_stringshare_replace(&wd->src_name_names[idx], s->name);
+ INF("source : %s", wd->src_name_names[idx]);
+ idx++;
+ }
+}
+
+static void
+_source_name_unload(Widget_Data *wd)
+{
+ int idx = 0;
+ Source_Name *s;
+
+ for (idx = 0; wd->src_name_names[idx]; idx++)
+ eina_stringshare_del(wd->src_name_names[idx]);
+ EINA_LIST_FREE(wd->src_names, s) free(s);
+ eina_module_list_free(wd->src_name_mods);
+}
+
+static void
+_source_name_set(Widget_Data *wd, const char *source_name)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ EINA_SAFETY_ON_NULL_RETURN(source_name);
+
+ Source_Name *s;
+ Eina_List *l;
+
+ if (wd->src_name && !strcmp(wd->src_name->name, source_name)) return;
+
+ EINA_LIST_FOREACH(wd->src_names, l, s)
+ {
+ if (!strcmp(s->name, source_name))
+ {
+ wd->src_name = s;
+ break;
+ }
+ }
+ if (!wd->src_name)
+ {
+ ERR("source name (%s) is not found", source_name);
+ return;
+ }
+}
+
+static void
+_source_all_load(Widget_Data *wd)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ _source_tile_load(wd);
+ _source_route_load(wd);
+ _source_name_load(wd);
+}
+
+static void
+_source_all_unload(Widget_Data *wd)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ _source_tile_unload(wd);
+ _source_route_unload(wd);
+ _source_name_unload(wd);
+}
+
+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_coord_get(dd->wd, NULL, NULL, &vw, &vh);
+
+ 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_do(dd->wd, zoom);
+ }
+}
+
+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;
+
+ _region_to_coord_convert(dd->wd, dd->lon, dd->lat, dd->wd->size.w, &x, &y);
+ _viewport_coord_get(dd->wd, NULL, NULL, &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 char *
+_mapnik_url_cb(const 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(const 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(const 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(const 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(const 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(const Evas_Object *obj __UNUSED__, const 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(const 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(const 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(const Evas_Object *obj, int method, const char *name, double lon, double lat)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype) strdup("");
+ Widget_Data *wd = elm_widget_data_get(obj);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wd, strdup(""));
+
+ char **str;
+ unsigned int ele, idx;
+ char search_url[PATH_MAX];
+ char buf[PATH_MAX];
+
+ 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, (int)wd->zoom);
+ else strcpy(buf, "");
+
+ 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)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype);
+ Widget_Data *wd = elm_widget_data_get(obj);
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ 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);
+ }
+}
+
+static void
+_del_hook(Evas_Object *obj)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype);
+ Widget_Data *wd = elm_widget_data_get(obj);
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ if (wd->map) evas_map_free(wd->map);
+ free(wd);
+}
+
+static void
+_del_pre_hook(Evas_Object *obj)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype);
+ Widget_Data *wd = elm_widget_data_get(obj);
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ Eina_List *l, *ll;
+ Elm_Map_Route *r;
+ Elm_Map_Name *na;
+ Evas_Object *track;
+ Elm_Map_Overlay *overlay;
+ Delayed_Data *dd;
+
+ EINA_LIST_FOREACH_SAFE(wd->routes, l, ll, r) elm_map_route_del(r);
+ eina_list_free(wd->routes);
+
+ EINA_LIST_FOREACH_SAFE(wd->names, l, ll, na) elm_map_name_del(na);
+ eina_list_free(wd->names);
+
+ EINA_LIST_FOREACH_SAFE(wd->overlays, l, ll, overlay)
+ elm_map_overlay_del(overlay);
+ eina_list_free(wd->overlays);