From 556807529ab8944e8a89ebb372fbf9dc562f32bd Mon Sep 17 00:00:00 2001 From: Serge Noiraud Date: Thu, 16 Jun 2011 17:44:41 +0000 Subject: [PATCH] Geography : cursor driven region and autozoom ( #0004882 ) svn: r17803 --- src/plugins/lib/maps/geography.py | 89 ++++++++++++++++++++++++------ src/plugins/lib/maps/grampsmaps.py | 76 +++++++++++++++++++++---- 2 files changed, 137 insertions(+), 28 deletions(-) diff --git a/src/plugins/lib/maps/geography.py b/src/plugins/lib/maps/geography.py index d0bbda333..ca83ae4a9 100644 --- a/src/plugins/lib/maps/geography.py +++ b/src/plugins/lib/maps/geography.py @@ -155,7 +155,6 @@ class PlaceSelection(ManagedWindow.ManagedWindow, osmGpsMap): self.oldvalue = oldvalue self.place_list = places self.function = function - self.selection_layer = None self.selection_layer = layer self.layer = layer alignment = gtk.Alignment(0,1,0,0) @@ -366,6 +365,7 @@ class GeoGraphyView(osmGpsMap, NavigationView): """Called when the page changes.""" NavigationView.change_page(self) self.uistate.clear_filter_results() + self.end_selection = None def on_delete(self): """ @@ -705,6 +705,70 @@ class GeoGraphyView(osmGpsMap, NavigationView): "%a %d %b %Y %H:%M:%S", time.gmtime())) self.uistate.set_busy_cursor(False) + def _visible_marker(self, lat, lon): + """ + Is this marker in the visible area ? + """ + bbox = self.osm.get_bbox() + s_lon = lon + 10.0 + s_lat = lat + 10.0 + s_bbox_lat1 = bbox[0] + 10.0 + s_bbox_lon1 = bbox[1] + 10.0 + s_bbox_lat2 = bbox[2] + 10.0 + s_bbox_lon2 = bbox[3] + 10.0 + result = ( s_bbox_lat1 > s_lat > s_bbox_lat2 ) and ( s_bbox_lon1 < s_lon < s_bbox_lon2 ) + return result + + def _autozoom_in(self, lvl, p1lat, p1lon, p2lat, p2lon): + """ + We zoom in until at least one marker missing. + """ + if ( ( self._visible_marker(p1lat, p1lon) + and self._visible_marker(p2lat, p2lon) ) + and lvl < 18 ): + lvl += 1 + self.osm.set_zoom(lvl) + gobject.timeout_add(150, self._autozoom_in, lvl, p1lat, p1lon, p2lat, p2lon) + else: + gobject.timeout_add(150, self._autozoom_out, lvl, p1lat, p1lon, p2lat, p2lon) + + def _autozoom_out(self, lvl, p1lat, p1lon, p2lat, p2lon): + """ + We zoom out until all markers visible. + """ + if ( not ( self._visible_marker(p1lat, p1lon) + and self._visible_marker(p2lat, p2lon) ) + and lvl > 1 ): + lvl -= 1 + self.osm.set_zoom(lvl) + gobject.timeout_add(150, self._autozoom_out, lvl, p1lat, p1lon, p2lat, p2lon) + else: + layer = self.get_selection_layer() + if layer: + self.osm.layer_remove(layer) + + def _autozoom(self): + """ + Try to put all markers on the map. we start at current zoom. + If all markers are present, continue to zoom. + If some markers are missing : return to the zoom - 1 + We must use function called by timeout to force map updates. + """ + level_start = self.osm.props.zoom + p1lat, p1lon = self.begin_selection.get_degrees() + p2lat, p2lon = self.end_selection.get_degrees() + lat = p1lat + ( p2lat - p1lat ) / 2 + lon = p1lon + ( p2lon - p1lon ) / 2 + # We center the map on the center of the region + self.osm.set_center(lat, lon) + self.save_center(lat, lon) + p1lat = self.begin_selection.rlat + p1lon = self.begin_selection.rlon + p2lat = self.end_selection.rlat + p2lon = self.end_selection.rlon + # We zoom in until at least one marker missing. + gobject.timeout_add(150, self._autozoom_in, level_start, p1lat, p1lon, p2lat, p2lon) + def _set_center_and_zoom(self): """ Calculate the zoom. @@ -720,7 +784,10 @@ class GeoGraphyView(osmGpsMap, NavigationView): signminlat = _get_sign(self.minlat) signmaxlon = _get_sign(self.maxlon) signmaxlat = _get_sign(self.maxlat) - # auto zoom ? + current = osmgpsmap.point_new_degrees(self.minlat, self.minlon) + self.end_selection = current + current = osmgpsmap.point_new_degrees(self.maxlat, self.maxlon) + self.begin_selection = current if signminlon == signmaxlon: maxlong = abs(abs(self.minlon) - abs(self.maxlon)) else: @@ -729,16 +796,6 @@ class GeoGraphyView(osmGpsMap, NavigationView): maxlat = abs(abs(self.minlat) - abs(self.maxlat)) else: maxlat = abs(abs(self.minlat) + abs(self.maxlat)) - # Calculate the zoom. all places must be displayed on the map. - zoomlat = _get_zoom_lat(maxlat) - zoomlong = _get_zoom_long(maxlong) - self.new_zoom = zoomlat if zoomlat < zoomlong else zoomlong - self.new_zoom -= 1 - if self.new_zoom < 2: - self.new_zoom = 2 - # We center the map on a point at the center of all markers - self.centerlat = maxlat/2 - self.centerlon = maxlong/2 latit = longt = 0.0 for mark in self.sort: if ( signminlat == signmaxlat ): @@ -762,19 +819,17 @@ class GeoGraphyView(osmGpsMap, NavigationView): # all maps: 0.0 for longitude and latitude means no location. if latit == longt == 0.0: latit = longt = 0.00000001 - self.mustcenter = False self.latit = latit self.longt = longt - if not (latit == longt == 0.0): - self.mustcenter = True if config.get("geography.lock"): self.osm.set_center_and_zoom(config.get("geography.center-lat"), config.get("geography.center-lon"), config.get("geography.zoom") ) else: - self.osm.set_center_and_zoom(self.latit, self.longt, self.new_zoom) + self._autozoom() + self.end_selection = None self.save_center(self.latit, self.longt) - config.set("geography.zoom",self.new_zoom) + config.set("geography.zoom",self.osm.props.zoom) def _get_father_and_mother_name(self, event): """ diff --git a/src/plugins/lib/maps/grampsmaps.py b/src/plugins/lib/maps/grampsmaps.py index fa038d653..d1d6535da 100644 --- a/src/plugins/lib/maps/grampsmaps.py +++ b/src/plugins/lib/maps/grampsmaps.py @@ -101,10 +101,14 @@ class SelectionLayer(gobject.GObject, osmgpsmap.GpsMapLayer): def __init__(self): gobject.GObject.__init__(self) self.circles = [] + self.rectangles = [] def add_circle(self, r, lat, lon): self.circles.append((r, lat, lon)) + def add_rectangle(self, p1, p2): + self.rectangles.append((p1, p2)) + def do_draw(self, gpsmap, drawable): gc = drawable.new_gc() for circle in self.circles: @@ -115,6 +119,21 @@ class SelectionLayer(gobject.GObject, osmgpsmap.GpsMapLayer): x, y = gpsmap.convert_geographic_to_screen(top_left) x2, y2 = gpsmap.convert_geographic_to_screen(bottom_right) drawable.draw_arc(gc, False, x, y, x2 - x, y2 - y, 0, 360*64) + for rectangle in self.rectangles: + top_left, bottom_right = rectangle + x, y = gpsmap.convert_geographic_to_screen(top_left) + x2, y2 = gpsmap.convert_geographic_to_screen(bottom_right) + # be sure when can select a region in all case. + if ( x < x2 ): + if ( y < y2 ): + drawable.draw_rectangle(gc, False, x, y, x2 - x, y2 - y) + else: + drawable.draw_rectangle(gc, False, x, y2, x2 - x, y - y2) + else: + if ( y < y2 ): + drawable.draw_rectangle(gc, False, x2, y, x - x2, y2 - y) + else: + drawable.draw_rectangle(gc, False, x2, y2, x - x2, y - y2) def do_render(self, gpsmap): pass @@ -132,8 +151,11 @@ class osmGpsMap(): self.cross_map = None self.osm = None self.show_tooltips = True + self.zone_selection = False self.selection_layer = None self.context_id = 0 + self.begin_selection = None + self.end_selection = None def build_widget(self): self.vbox = gtk.VBox(False, 0) @@ -170,6 +192,7 @@ class osmGpsMap(): self.osm = osmgpsmap.GpsMap(tile_cache=tiles_path, map_source=constants.map_type[map_type]) current_map = osmgpsmap.GpsMapOsd( show_dpad=False, show_zoom=True) + self.end_selection = None self.osm.layer_add(current_map) self.osm.layer_add(DummyLayer()) self.selection_layer = self.add_selection_layer() @@ -180,8 +203,9 @@ class osmGpsMap(): config.get("geography.zoom") ) self.osm.connect('button_release_event', self.map_clicked) - self.osm.connect('changed', self.zoom_changed) + self.osm.connect('button_press_event', self.map_clicked) self.osm.connect("motion-notify-event", self.motion_event) + self.osm.connect('changed', self.zoom_changed) self.osm.show() self.vbox.pack_start(self.osm) if obj is not None: @@ -209,14 +233,25 @@ class osmGpsMap(): current = osmgpsmap.point_new_degrees(0.0,0.0) osmmap.convert_screen_to_geographic(int(event.x), int(event.y), current) lat, lon = current.get_degrees() - places = self.is_there_a_place_here(lat, lon) - mess = "" - for p in places: - if mess != "": - mess += " || " - mess += p[0] - self.uistate.status.pop(self.context_id) - self.context_id = self.uistate.status.push(1, mess) + if self.zone_selection: + # We draw a rectangle to show the selected region. + layer = self.get_selection_layer() + if layer: + self.osm.layer_remove(layer) + self.selection_layer = self.add_selection_layer() + if self.end_selection == None: + self.selection_layer.add_rectangle(self.begin_selection, current) + else: + self.selection_layer.add_rectangle(self.begin_selection, self.end_selection) + else: + places = self.is_there_a_place_here(lat, lon) + mess = "" + for p in places: + if mess != "": + mess += " || " + mess += p[0] + self.uistate.status.pop(self.context_id) + self.context_id = self.uistate.status.push(1, mess) def save_center(self, lat, lon): """ @@ -225,11 +260,30 @@ class osmGpsMap(): config.set("geography.center-lat",lat) config.set("geography.center-lon",lon) + def activate_selection_zoom(self, osm, event): + if self.end_selection is not None: + self._autozoom() + return True + def map_clicked(self, osm, event): lat,lon = self.osm.get_event_location(event).get_degrees() + current = osmgpsmap.point_new_degrees(0.0,0.0) + osm.convert_screen_to_geographic(int(event.x), int(event.y), current) + lat, lon = current.get_degrees() if event.button == 1: - # do we click on a marker ? - marker = self.is_there_a_marker_here(event, lat, lon) + if self.end_selection is not None: + self.activate_selection_zoom(osm, event) + self.end_selection = None + else: + # do we click on a marker ? + marker = self.is_there_a_marker_here(event, lat, lon) + elif event.button == 2 and event.type == gtk.gdk.BUTTON_PRESS: + self.begin_selection = current + self.end_selection = None + self.zone_selection = True + elif event.button == 2 and event.type == gtk.gdk.BUTTON_RELEASE: + self.end_selection = current + self.zone_selection = False elif event.button == 3: self.build_nav_menu(osm, event, lat, lon ) else: