/* * Copyright (C) 2010 Mathieu Baudier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.argeo.gis.ui.rcp.swing; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.Point2D; import javax.swing.SwingUtilities; import javax.swing.event.MouseInputAdapter; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.Envelope2D; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.swing.JMapPane; import org.geotools.swing.event.MapMouseEvent; import org.geotools.swing.tool.AbstractZoomTool; public class VersatileZoomTool extends AbstractZoomTool { // private Log log = LogFactory.getLog(VersatileZoomTool.class); // private static final ResourceBundle stringRes = ResourceBundle // .getBundle("org/geotools/swing/Text"); // Cursors private Cursor zoomInCursor; private Cursor panCursor; private Cursor defaultCursor; // Variable values private Point2D startDragPos; private Point panePos; private boolean computingZoomBox; private boolean panning; private Point2D fieldPosition; /** * Constructor */ public VersatileZoomTool() { // Toolkit tk = Toolkit.getDefaultToolkit(); // zoomInCursor = tk.createCustomCursor(new ImageIcon(getClass() // .getResource("/org/geotools/swing/icons/mActionZoomIn.png")) // .getImage(), new Point(14, 9), stringRes // .getString("tool_name_zoom_in")); zoomInCursor = new Cursor(Cursor.SE_RESIZE_CURSOR); // panCursor = tk.createCustomCursor(new // ImageIcon(getClass().getResource( // "/org/geotools/swing/icons/mActionPan.png")).getImage(), // new Point(15, 15), stringRes.getString("tool_name_pan")); panCursor = new Cursor(Cursor.HAND_CURSOR); defaultCursor = new Cursor(Cursor.CROSSHAIR_CURSOR); startDragPos = new DirectPosition2D(); computingZoomBox = false; panning = false; } /** * Zoom in by the currently set increment, with the map centred at the * location (in world coords) of the mouse click * * @param e * map mapPane mouse event */ @Override public void onMouseClicked(MapMouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) centerMapToEvent(e, getZoom()); else if (SwingUtilities.isRightMouseButton(e)) centerMapToEvent(e, 1 / getZoom()); else if (SwingUtilities.isMiddleMouseButton(e)) { if (fieldPosition != null) { Envelope2D env = new Envelope2D(); final double increment = 0.1d; env.setFrameFromDiagonal(fieldPosition.getX() - increment, fieldPosition.getY() - increment, fieldPosition.getX() + increment, fieldPosition.getY() + increment); getMapPane().setDisplayArea(env); } } } protected void centerMapToEvent(MapMouseEvent e, Double zoomArg) { Rectangle paneArea = getMapPane().getVisibleRect(); DirectPosition2D mapPos = e.getMapPosition(); double scale = getMapPane().getWorldToScreenTransform().getScaleX(); double newScale = scale * zoomArg; DirectPosition2D corner = new DirectPosition2D(mapPos.getX() - 0.5d * paneArea.getWidth() / newScale, mapPos.getY() + 0.5d * paneArea.getHeight() / newScale); Envelope2D newMapArea = new Envelope2D(); newMapArea.setFrameFromCenter(mapPos, corner); getMapPane().setDisplayArea(newMapArea); } /** * Records the map position of the mouse event in case this button press is * the beginning of a mouse drag * * @param ev * the mouse event */ @Override public void onMousePressed(MapMouseEvent ev) { if (SwingUtilities.isLeftMouseButton(ev)) { startDragPos = new DirectPosition2D(); startDragPos.setLocation(ev.getMapPosition()); } else if (SwingUtilities.isMiddleMouseButton(ev) || SwingUtilities.isRightMouseButton(ev)) { panePos = ev.getPoint(); panning = true; } } /** * Records that the mouse is being dragged * * @param ev * the mouse event */ @Override public void onMouseDragged(MapMouseEvent ev) { if (SwingUtilities.isLeftMouseButton(ev)) { computingZoomBox = true; } else if (panning) { Point pos = ev.getPoint(); if (!pos.equals(panePos)) { getMapPane().moveImage(pos.x - panePos.x, pos.y - panePos.y); panePos = pos; } } getMapPane().setCursor(getCursor()); } /** * If the mouse was dragged, determines the bounds of the box that the user * defined and passes this to the mapPane's * {@link org.geotools.swing.JMapPane#setDisplayArea(org.opengis.geometry.Envelope) } * method * * @param ev * the mouse event */ @Override public void onMouseReleased(MapMouseEvent ev) { if (computingZoomBox && !ev.getPoint().equals(startDragPos)) { Envelope2D env = new Envelope2D(); env.setFrameFromDiagonal(startDragPos, ev.getMapPosition()); computingZoomBox = false; getMapPane().setDisplayArea(env); } else if (panning) { panning = false; getMapPane().repaint(); } getMapPane().setCursor(getCursor()); } /** * Get the mouse cursor for this tool */ @Override public Cursor getCursor() { if (computingZoomBox) return zoomInCursor; else if (panning) return panCursor; else return defaultCursor; } /** * We use a custom drag box */ @Override public boolean drawDragBox() { return false; } @Override public void setMapPane(JMapPane pane) { super.setMapPane(pane); VariableDragBox dragBox = new VariableDragBox(); getMapPane().addMouseListener(dragBox); getMapPane().addMouseMotionListener(dragBox); getMapPane().addMouseWheelListener(new MouseWheelListener() { private double clickToZoom = 0.1; // 1 wheel click is 10% zoom public void mouseWheelMoved(MouseWheelEvent ev) { int clicks = ev.getWheelRotation(); // -ve means wheel moved up, +ve means down int sign = (clicks < 0 ? -1 : 1); ReferencedEnvelope env = getMapPane().getDisplayArea(); if (env == null) return; double width = env.getWidth(); double delta = width * clickToZoom * sign; env.expandBy(delta); getMapPane().setDisplayArea(env); getMapPane().repaint(); } }); } public void setFieldPosition(Point2D fieldPosition) { this.fieldPosition = fieldPosition; } /** * Custom drag box (hacked from JMapPane) so that we can change the behavior * depending on whether we pan or zoom. */ private class VariableDragBox extends MouseInputAdapter { private Point startPos; private Rectangle rect; private boolean dragged; VariableDragBox() { rect = new Rectangle(); dragged = false; } @Override public void mousePressed(MouseEvent e) { startPos = new Point(e.getPoint()); } @Override public void mouseDragged(MouseEvent e) { if (computingZoomBox) { Graphics2D g2D = (Graphics2D) getMapPane().getGraphics(); g2D.setColor(Color.WHITE); g2D.setXORMode(Color.RED); if (dragged) { g2D.drawRect(rect.x, rect.y, rect.width, rect.height); } rect.setFrameFromDiagonal(startPos, e.getPoint()); g2D.drawRect(rect.x, rect.y, rect.width, rect.height); dragged = true; } } @Override public void mouseReleased(MouseEvent e) { if (dragged) { Graphics2D g2D = (Graphics2D) getMapPane().getGraphics(); g2D.setColor(Color.WHITE); g2D.setXORMode(Color.RED); g2D.drawRect(rect.x, rect.y, rect.width, rect.height); dragged = false; } } } }