source: josm/trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapControler.java@ 4474

Last change on this file since 4474 was 4474, checked in by Don-vip, 13 years ago

fix #6794 - download dialog slippymap: mouseup on licence text instead of click

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1// This code has been adapted and copied from code that has been written by Immanuel Scholz and others for JOSM.
2// License: GPL. Copyright 2007 by Tim Haussmann
3package org.openstreetmap.josm.gui.bbox;
4
5import java.awt.Point;
6import java.awt.event.ActionEvent;
7import java.awt.event.InputEvent;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.awt.event.MouseListener;
12import java.awt.event.MouseMotionListener;
13import java.util.Timer;
14import java.util.TimerTask;
15
16import javax.swing.AbstractAction;
17import javax.swing.ActionMap;
18import javax.swing.InputMap;
19import javax.swing.JComponent;
20import javax.swing.JPanel;
21import javax.swing.KeyStroke;
22
23
24/**
25 * This class controls the user input by listening to mouse and key events.
26 * Currently implemented is: - zooming in and out with scrollwheel - zooming in
27 * and centering by double clicking - selecting an area by clicking and dragging
28 * the mouse
29 *
30 * @author Tim Haussmann
31 */
32public class SlippyMapControler extends MouseAdapter implements MouseMotionListener, MouseListener {
33
34 /** A Timer for smoothly moving the map area */
35 private static final Timer timer = new Timer(true);
36
37 /** Does the moving */
38 private MoveTask moveTask = new MoveTask();
39
40 /** How often to do the moving (milliseconds) */
41 private static long timerInterval = 20;
42
43 /** The maximum speed (pixels per timer interval) */
44 private static final double MAX_SPEED = 20;
45
46 /** The speed increase per timer interval when a cursor button is clicked */
47 private static final double ACCELERATION = 0.10;
48
49 // start and end point of selection rectangle
50 private Point iStartSelectionPoint;
51 private Point iEndSelectionPoint;
52
53 // the SlippyMapChooserComponent
54 private final SlippyMapBBoxChooser iSlippyMapChooser;
55
56 private SizeButton iSizeButton = null;
57 private SourceButton iSourceButton = null;
58
59 private boolean isSelecting;
60
61 /**
62 * Create a new OsmMapControl
63 */
64 public SlippyMapControler(SlippyMapBBoxChooser navComp, JPanel contentPane, SizeButton sizeButton, SourceButton sourceButton) {
65 this.iSlippyMapChooser = navComp;
66 iSlippyMapChooser.addMouseListener(this);
67 iSlippyMapChooser.addMouseMotionListener(this);
68
69 String[] n = { ",", ".", "up", "right", "down", "left" };
70 int[] k = { KeyEvent.VK_COMMA, KeyEvent.VK_PERIOD, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN,
71 KeyEvent.VK_LEFT };
72
73 if (contentPane != null) {
74 for (int i = 0; i < n.length; ++i) {
75 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
76 KeyStroke.getKeyStroke(k[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer." + n[i]);
77 }
78 }
79 iSizeButton = sizeButton;
80 iSourceButton = sourceButton;
81
82 isSelecting = false;
83
84 InputMap inputMap = navComp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
85 ActionMap actionMap = navComp.getActionMap();
86
87 // map moving
88 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "MOVE_RIGHT");
89 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "MOVE_LEFT");
90 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "MOVE_UP");
91 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "MOVE_DOWN");
92 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "STOP_MOVE_HORIZONTALLY");
93 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "STOP_MOVE_HORIZONTALLY");
94 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "STOP_MOVE_VERTICALLY");
95 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "STOP_MOVE_VERTICALLY");
96
97 // zooming. To avoid confusion about which modifier key to use,
98 // we just add all keys left of the space bar
99 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK, false), "ZOOM_IN");
100 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.META_DOWN_MASK, false), "ZOOM_IN");
101 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK, false), "ZOOM_IN");
102 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK, false), "ZOOM_OUT");
103 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.META_DOWN_MASK, false), "ZOOM_OUT");
104 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK, false), "ZOOM_OUT");
105
106 // action mapping
107 actionMap.put("MOVE_RIGHT", new MoveXAction(1));
108 actionMap.put("MOVE_LEFT", new MoveXAction(-1));
109 actionMap.put("MOVE_UP", new MoveYAction(-1));
110 actionMap.put("MOVE_DOWN", new MoveYAction(1));
111 actionMap.put("STOP_MOVE_HORIZONTALLY", new MoveXAction(0));
112 actionMap.put("STOP_MOVE_VERTICALLY", new MoveYAction(0));
113 actionMap.put("ZOOM_IN", new ZoomInAction());
114 actionMap.put("ZOOM_OUT", new ZoomOutAction());
115 }
116
117 /**
118 * Start drawing the selection rectangle if it was the 1st button (left
119 * button)
120 */
121 @Override
122 public void mousePressed(MouseEvent e) {
123 if (e.getButton() == MouseEvent.BUTTON1) {
124 if (!iSizeButton.hit(e.getPoint())) {
125 iStartSelectionPoint = e.getPoint();
126 iEndSelectionPoint = e.getPoint();
127 }
128 }
129
130 }
131
132 @Override
133 public void mouseDragged(MouseEvent e) {
134 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) {
135 if (iStartSelectionPoint != null) {
136 iEndSelectionPoint = e.getPoint();
137 iSlippyMapChooser.setSelection(iStartSelectionPoint, iEndSelectionPoint);
138 isSelecting = true;
139 }
140 }
141 }
142
143 /**
144 * When dragging the map change the cursor back to it's pre-move cursor. If
145 * a double-click occurs center and zoom the map on the clicked location.
146 */
147 @Override
148 public void mouseReleased(MouseEvent e) {
149 if (e.getButton() == MouseEvent.BUTTON1) {
150
151 if (isSelecting && e.getClickCount() == 1) {
152 iSlippyMapChooser.setSelection(iStartSelectionPoint, e.getPoint());
153
154 // reset the selections start and end
155 iEndSelectionPoint = null;
156 iStartSelectionPoint = null;
157 isSelecting = false;
158
159 } else {
160 int sourceButton = iSourceButton.hit(e.getPoint());
161
162 if (iSizeButton.hit(e.getPoint())) {
163 iSizeButton.toggle();
164 iSlippyMapChooser.resizeSlippyMap();
165 } else if (iSlippyMapChooser.handleAttribution(e.getPoint(), true)) {
166 /* do nothing, handleAttribution() already did the work */
167 } else if (sourceButton == SourceButton.HIDE_OR_SHOW) {
168 iSourceButton.toggle();
169 iSlippyMapChooser.repaint();
170 } else if (sourceButton != 0) {
171 iSlippyMapChooser.toggleMapSource(iSourceButton.hitToTileSource(sourceButton));
172 }
173 }
174 }
175 }
176
177 @Override
178 public void mouseMoved(MouseEvent e) {
179 iSlippyMapChooser.handleAttribution(e.getPoint(), false);
180 }
181
182 private class MoveXAction extends AbstractAction {
183
184 int direction;
185
186 public MoveXAction(int direction) {
187 this.direction = direction;
188 }
189
190 public void actionPerformed(ActionEvent e) {
191 moveTask.setDirectionX(direction);
192 }
193 }
194
195 private class MoveYAction extends AbstractAction {
196
197 int direction;
198
199 public MoveYAction(int direction) {
200 this.direction = direction;
201 }
202
203 public void actionPerformed(ActionEvent e) {
204 moveTask.setDirectionY(direction);
205 }
206 }
207
208 /** Moves the map depending on which cursor keys are pressed (or not) */
209 private class MoveTask extends TimerTask {
210 /** The current x speed (pixels per timer interval) */
211 private double speedX = 1;
212
213 /** The current y speed (pixels per timer interval) */
214 private double speedY = 1;
215
216 /** The horizontal direction of movement, -1:left, 0:stop, 1:right */
217 private int directionX = 0;
218
219 /** The vertical direction of movement, -1:up, 0:stop, 1:down */
220 private int directionY = 0;
221
222 /**
223 * Indicated if <code>moveTask</code> is currently enabled (periodically
224 * executed via timer) or disabled
225 */
226 protected boolean scheduled = false;
227
228 protected void setDirectionX(int directionX) {
229 this.directionX = directionX;
230 updateScheduleStatus();
231 }
232
233 protected void setDirectionY(int directionY) {
234 this.directionY = directionY;
235 updateScheduleStatus();
236 }
237
238 private void updateScheduleStatus() {
239 boolean newMoveTaskState = !(directionX == 0 && directionY == 0);
240
241 if (newMoveTaskState != scheduled) {
242 scheduled = newMoveTaskState;
243 if (newMoveTaskState) {
244 timer.schedule(this, 0, timerInterval);
245 } else {
246 // We have to create a new instance because rescheduling a
247 // once canceled TimerTask is not possible
248 moveTask = new MoveTask();
249 cancel(); // Stop this TimerTask
250 }
251 }
252 }
253
254 @Override
255 public void run() {
256 // update the x speed
257 switch (directionX) {
258 case -1:
259 if (speedX > -1) {
260 speedX = -1;
261 }
262 if (speedX > -1 * MAX_SPEED) {
263 speedX -= ACCELERATION;
264 }
265 break;
266 case 0:
267 speedX = 0;
268 break;
269 case 1:
270 if (speedX < 1) {
271 speedX = 1;
272 }
273 if (speedX < MAX_SPEED) {
274 speedX += ACCELERATION;
275 }
276 break;
277 }
278
279 // update the y speed
280 switch (directionY) {
281 case -1:
282 if (speedY > -1) {
283 speedY = -1;
284 }
285 if (speedY > -1 * MAX_SPEED) {
286 speedY -= ACCELERATION;
287 }
288 break;
289 case 0:
290 speedY = 0;
291 break;
292 case 1:
293 if (speedY < 1) {
294 speedY = 1;
295 }
296 if (speedY < MAX_SPEED) {
297 speedY += ACCELERATION;
298 }
299 break;
300 }
301
302 // move the map
303 int moveX = (int) Math.floor(speedX);
304 int moveY = (int) Math.floor(speedY);
305 if (moveX != 0 || moveY != 0) {
306 iSlippyMapChooser.moveMap(moveX, moveY);
307 }
308 }
309 }
310
311 private class ZoomInAction extends AbstractAction {
312
313 public void actionPerformed(ActionEvent e) {
314 iSlippyMapChooser.zoomIn();
315 }
316 }
317
318 private class ZoomOutAction extends AbstractAction {
319
320 public void actionPerformed(ActionEvent e) {
321 iSlippyMapChooser.zoomOut();
322 }
323 }
324}
Note: See TracBrowser for help on using the repository browser.