/*
This file is part of RouteConverter.
RouteConverter is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
RouteConverter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RouteConverter; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 2007 Christian Pesch. All Rights Reserved.
*/
package slash.navigation.mapview.mapsforge.helpers;
import org.mapsforge.core.model.Dimension;
import org.mapsforge.core.model.LatLong;
import org.mapsforge.map.layer.Layer;
import org.mapsforge.map.layer.LayerManager;
import org.mapsforge.map.model.MapViewPosition;
import org.mapsforge.map.util.MapViewProjection;
import slash.navigation.mapview.mapsforge.AwtGraphicMapView;
import slash.navigation.mapview.mapsforge.overlays.DraggableMarker;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import static java.lang.Thread.sleep;
import static javax.swing.SwingUtilities.isLeftMouseButton;
import static slash.navigation.gui.helpers.UIHelper.startDragCursor;
import static slash.navigation.gui.helpers.UIHelper.stopWaitCursor;
/**
* Move and zoom map upon mouse events of the {@link AwtGraphicMapView}.
*
* @author Christian Pesch
*/
public class MapViewMoverAndZoomer extends MouseAdapter {
private static final int STEPS_TO_MOVE_CENTER = 25;
private final AwtGraphicMapView mapView;
private final MapViewProjection projection;
private final LayerManager layerManager;
private Point lastMousePressPoint;
private DraggableMarker mousePressMarker;
public MapViewMoverAndZoomer(AwtGraphicMapView mapView, LayerManager layerManager) {
this.mapView = mapView;
this.projection = new MapViewProjection(mapView);
this.layerManager = layerManager;
mapView.addMouseListener(this);
mapView.addMouseMotionListener(this);
mapView.addMouseWheelListener(this);
}
public void mousePressed(MouseEvent e) {
mousePressMarker = getMarkerFor(e);
if (mousePressMarker == null)
lastMousePressPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
if (isLeftMouseButton(e)) {
if (isMousePressedOnMarker()) {
startDragCursor(mapView);
LatLong latLong = projection.fromPixels(e.getX(), e.getY());
mousePressMarker.setLatLong(latLong);
mousePressMarker.requestRedraw();
} else if (getLastMousePoint() != null) {
Point point = e.getPoint();
int moveHorizontal = point.x - lastMousePressPoint.x;
int moveVertical = point.y - lastMousePressPoint.y;
mapView.getModel().mapViewPosition.moveCenter(moveHorizontal, moveVertical);
lastMousePressPoint = point;
}
}
}
public void mouseReleased(MouseEvent e) {
if (isMousePressedOnMarker()) {
LatLong latLong = projection.fromPixels(e.getX(), e.getY());
mousePressMarker.onDrop(latLong);
mousePressMarker = null;
stopWaitCursor(mapView);
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
lastMousePressPoint = e.getPoint();
zoomToMousePosition((byte) -e.getWheelRotation());
}
private DraggableMarker getMarkerFor(MouseEvent e) {
LatLong tapLatLong = projection.fromPixels(e.getX(), e.getY());
org.mapsforge.core.model.Point tapXY = new org.mapsforge.core.model.Point(e.getX(), e.getY());
for (int i = layerManager.getLayers().size() - 1; i >= 0; --i) {
Layer layer = layerManager.getLayers().get(i);
if (!(layer instanceof DraggableMarker))
continue;
org.mapsforge.core.model.Point layerXY = projection.toPixels(layer.getPosition());
if (layer.onTap(tapLatLong, layerXY, tapXY))
return DraggableMarker.class.cast(layer);
}
return null;
}
public void centerToMousePosition() {
Dimension dimension = mapView.getDimension();
int horizontalDiff = dimension.width / 2 - lastMousePressPoint.x;
int verticalDiff = dimension.height / 2 - lastMousePressPoint.y;
animateCenter(horizontalDiff, verticalDiff);
}
public void animateCenter(final int horizontalDiff, final int verticalDiff) {
new Thread(new Runnable() {
public void run() {
double stepSizeX = horizontalDiff / (double)STEPS_TO_MOVE_CENTER;
double stepSizeY = verticalDiff / (double)STEPS_TO_MOVE_CENTER;
for (int i = 0; i < STEPS_TO_MOVE_CENTER; i++) {
mapView.getModel().mapViewPosition.moveCenter(stepSizeX, stepSizeY);
try {
sleep(10);
} catch (InterruptedException e) {
// intentionally left empty
}
}
}
}).start();
}
public void zoomToMousePosition(byte zoomLevelDiff) {
if (zoomLevelDiff == 0 || lastMousePressPoint == null)
return;
zoomToMousePosition(zoomLevelDiff, lastMousePressPoint.x, lastMousePressPoint.y);
}
private void zoomToMousePosition(byte zoomLevelDiff, int mouseX, int mouseY) {
LatLong mouse = projection.fromPixels(mouseX, mouseY);
MapViewPosition mapViewPosition = mapView.getModel().mapViewPosition;
mapViewPosition.setPivot(mouse);
if (mapViewPosition.getZoomLevel() + zoomLevelDiff <= mapViewPosition.getZoomLevelMax() &&
mapViewPosition.getZoomLevel() + zoomLevelDiff >= mapViewPosition.getZoomLevelMin()) {
Dimension dimension = mapView.getDimension();
int horizontalDiff = (int) ((dimension.width / 2 - mouseX) * (zoomLevelDiff > 0 ? 0.5 : -1.0));
int verticalDiff = (int) ((dimension.height / 2 - mouseY) * (zoomLevelDiff > 0 ? 0.5 : -1.0));
mapViewPosition.moveCenterAndZoom(horizontalDiff, verticalDiff, zoomLevelDiff);
}
}
public Point getLastMousePoint() {
return lastMousePressPoint;
}
public boolean isMousePressedOnMarker() {
return mousePressMarker != null;
}
}