+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},
+};
+
+// FIXME: Fix more open sources
+const Source_Route src_routes[] =
+{
+ {"Yours", _yours_url_cb} // http://www.yournavigation.org/
+ //{"Monav", _monav_url_cb},
+ //{"ORS", _ors_url_cb}, // http://www.openrouteservice.org
+};
+
+// FIXME: Add more open sources
+const Source_Name src_names[] =
+{
+ {"Nominatim", _nominatim_url_cb}
+};
+
+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_CLICKED[] = "clicked";
+static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
+static const char SIG_PRESS[] = "press";
+static const char SIG_LONGPRESSED[] = "longpressed";
+static const char SIG_SCROLL[] = "scroll";
+static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
+static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
+static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
+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_TILE_LOAD[] = "tile,load";
+static const char SIG_TILE_LOADED[] = "tile,loaded";
+static const char SIG_TILE_LOADED_FAIL[] = "tile,loaded,fail";
+static const char SIG_ROUTE_LOAD[] = "route,load";
+static const char SIG_ROUTE_LOADED[] = "route,loaded";
+static const char SIG_ROUTE_LOADED_FAIL[] = "route,loaded,fail";
+static const char SIG_NAME_LOAD[] = "name,load";
+static const char SIG_NAME_LOADED[] = "name,loaded";
+static const char SIG_NAME_LOADED_FAIL[] = "name,loaded,fail";
+static const char SIG_OVERLAY_CLICKED[] = "overlay,clicked";
+static const Evas_Smart_Cb_Description _signals[] = {
+ {SIG_CLICKED, ""},
+ {SIG_CLICKED_DOUBLE, ""},
+ {SIG_PRESS, ""},
+ {SIG_LONGPRESSED, ""},
+ {SIG_SCROLL, ""},
+ {SIG_SCROLL_DRAG_START, ""},
+ {SIG_SCROLL_DRAG_STOP, ""},
+ {SIG_SCROLL_ANIM_START, ""},
+ {SIG_SCROLL_ANIM_STOP, ""},
+ {SIG_ZOOM_START, ""},
+ {SIG_ZOOM_STOP, ""},
+ {SIG_ZOOM_CHANGE, ""},
+ {SIG_TILE_LOAD, ""},
+ {SIG_TILE_LOADED, ""},
+ {SIG_TILE_LOADED_FAIL, ""},
+ {SIG_ROUTE_LOAD, ""},
+ {SIG_ROUTE_LOADED, ""},
+ {SIG_ROUTE_LOADED_FAIL, ""},
+ {SIG_NAME_LOAD, ""},
+ {SIG_NAME_LOADED, ""},
+ {SIG_NAME_LOADED_FAIL, ""},
+ {SIG_OVERLAY_CLICKED, ""},
+ {NULL, NULL}
+};
+
+static void
+_edj_marker_size_get(Widget_Data *wd, Evas_Coord *w, Evas_Coord *h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+ EINA_SAFETY_ON_NULL_RETURN(w);
+ EINA_SAFETY_ON_NULL_RETURN(h);
+
+ 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
+_coord_rotate(Evas_Coord x, Evas_Coord y, Evas_Coord cx, Evas_Coord cy, double degree, Evas_Coord *xx, Evas_Coord *yy)
+{
+ EINA_SAFETY_ON_NULL_RETURN(xx);
+ EINA_SAFETY_ON_NULL_RETURN(yy);
+
+ double r = (degree * M_PI) / 180.0;
+
+ if (xx) *xx = ((x - cx) * cos(r)) + ((y - cy) * cos(r + M_PI_2)) + cx;
+ if (yy) *yy = ((x - cx) * sin(r)) + ((y - cy) * sin(r + M_PI_2)) + cy;
+}
+
+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);
+
+ evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+ evas_object_image_size_get(obj, &w, &h);
+ if ((w > ow) || (h > oh))
+ {
+ 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
+_obj_place(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(obj);
+
+ evas_object_move(obj, x, y);
+ evas_object_resize(obj, w, h);
+ evas_object_show(obj);
+}
+
+static void
+_coord_to_region_convert(Widget_Data *wd, Evas_Coord x, Evas_Coord y, Evas_Coord size, double *lon, double *lat)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ int zoom = floor(log(size / wd->size.tile) / log(2));
+ if ((wd->src_tile) && (wd->src_tile->coord_to_geo))
+ {
+ if (wd->src_tile->coord_to_geo(wd->obj, zoom, x, y, size, lon, lat))
+ return;
+ }
+
+ if (lon) *lon = (x / (double)size * 360.0) - 180;
+ if (lat)
+ {
+ double n = ELM_PI - (2.0 * ELM_PI * y / size);
+ *lat = 180.0 / ELM_PI * atan(0.5 * (exp(n) - exp(-n)));
+ }
+}
+
+static void
+_region_to_coord_convert(Widget_Data *wd, double lon, double lat, Evas_Coord size, Evas_Coord *x, Evas_Coord *y)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ int zoom = floor(log(size / 256) / log(2));
+ if ((wd->src_tile) && (wd->src_tile->geo_to_coord))
+ {
+ 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)))
+ / ELM_PI) / 2.0 * size);
+}
+
+static void
+_viewport_size_get(Widget_Data *wd, Evas_Coord *vw, Evas_Coord *vh)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ 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
+_pan_geometry_get(Widget_Data *wd, Evas_Coord *px, Evas_Coord *py)
+{
+ EINA_SAFETY_ON_NULL_RETURN(wd);
+
+ 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;
+ }
+
+static void
+_region_show(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_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 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_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_region_bring_in(marker->wd->obj, marker->longitude, marker->latitude);
+}
+
+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
+_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;
+ Evas_Coord px, py;
+
+ if (wd->paused_markers || (!eina_list_count(wd->markers))) return;
+
+ _pan_geometry_get(wd, &px, &py);
+
+ _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_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);
+ }
+ }
+
+ 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_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);
+>>>>>>> remotes/origin/upstream
+ }
+ }
+}
+
+static void
+<<<<<<< HEAD
+_smooth_update(Evas_Object *obj)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype);
+ Widget_Data *wd = elm_widget_data_get(obj);
+ Eina_List *l;
+ Grid *g;
+
+ if (!wd) return;
+ EINA_LIST_FOREACH(wd->grids, l, g)
+ {
+ Eina_Iterator *it = eina_matrixsparse_iterator_new(g->grid);
+ Eina_Matrixsparse_Cell *cell;
+
+ 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);
+ }
+}
+
+static Eina_Bool
+_scr_timeout(void *data)
+{
+ 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;
+}
+
+static void
+_scr(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+ ELM_CHECK_WIDTYPE(data, widtype);
+ Widget_Data *wd = elm_widget_data_get(data);
+
+ if (!wd) return;
+ if (!wd->scr_timer)
+ {
+ wd->nosmooth++;
+ if (wd->nosmooth == 1) _smooth_update(data);
+ }
+ if (wd->scr_timer) ecore_timer_del(wd->scr_timer);
+ wd->scr_timer = ecore_timer_add(0.5, _scr_timeout, data);
+}
+
+static void
+zoom_do(Evas_Object *obj)
+{
+ ELM_CHECK_WIDTYPE(obj, widtype);
+ Widget_Data *wd = elm_widget_data_get(obj);
+ Evas_Coord xx, yy, ow, oh;
+
+ if (!wd) return;
+ wd->size.w = wd->size.nw;
+ wd->size.h = wd->size.nh;
+
+ elm_smart_scroller_child_viewport_size_get(wd->scr, &ow, &oh);
+
+ if (wd->center_on.enabled)
+ {
+ 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;
+ }
+ else
+ {
+ xx = (wd->size.spos.x * wd->size.w) - (ow / 2);
+ yy = (wd->size.spos.y * wd->size.h) - (oh / 2);
+ }
+
+
+ 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;
+
+ wd->show.show = EINA_TRUE;
+ wd->show.x = xx;
+ wd->show.y = yy;
+ wd->show.w = ow;
+ wd->show.h = oh;
+
+ if (wd->calc_job) ecore_job_del(wd->calc_job);
+ wd->calc_job = ecore_job_add(_calc_job, wd);
+}
+
+static Eina_Bool
+_zoom_timeout(void *data)
+{
+ ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
+ Widget_Data *wd = elm_widget_data_get(data);
+
+ 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;
+}
+
+static Eina_Bool
+_zoom_anim(void *data)
+{
+ ELM_CHECK_WIDTYPE(data, widtype) ECORE_CALLBACK_CANCEL;
+ Evas_Object *obj = data;
+ Widget_Data *wd = elm_widget_data_get(obj);
+
+ 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
+ {
+ wd->zoom_animator = NULL;
+ zoom_do(obj);
+ evas_object_smart_callback_call(data, SIG_ZOOM_STOP, NULL);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (wd->t >= 2.0)
+ {
+ 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;
+ }
+ else if (wd->t <= 0.5)
+ {
+ 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;
+ }
+ else if (wd->t != 1.0)
+ {
+ 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);
+=======
+_grid_item_coord_get(Grid_Item *gi, int *x, int *y, int *w, int *h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(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;
+}
+
+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
+_grid_item_update(Grid_Item *gi)
+{
+ 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);
+
+ 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
+ {
+ Evas_Coord px, py;
+ Evas_Coord x, y, w, h;
+
+ _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 void
+_grid_item_load(Grid_Item *gi)
+{
+ 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
+_grid_item_unload(Grid_Item *gi)
+{
+ 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 *url;
+ 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);
+
+ snprintf(buf, sizeof(buf), CACHE_TILE_ROOT, g->wd->id, g->zoom, x);
+ snprintf(buf2, sizeof(buf2), CACHE_TILE_PATH, buf, y);
+ if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
+
+ eina_stringshare_replace(&gi->file, buf2);
+ url = g->wd->src_tile->url_cb(g->wd->obj, x, y, g->zoom);
+ if ((!url) || (!strlen(url)))
+ {
+ eina_stringshare_replace(&gi->url, NULL);
+ ERR("Getting source url failed: %s", gi->file);
+ }
+ else eina_stringshare_replace(&gi->url, url);
+ if (url) free(url);
+ eina_matrixsparse_data_idx_set(g->grid, y, x, gi);
+ return gi;
+}
+
+static void
+_grid_item_free(Grid_Item *gi)