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

Last change on this file since 6070 was 6070, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 11.5 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_ADD, 0, false), "ZOOM_IN");
103 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK, false), "ZOOM_OUT");
104 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.META_DOWN_MASK, false), "ZOOM_OUT");
105 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK, false), "ZOOM_OUT");
106 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0, false), "ZOOM_OUT");
107
108 // action mapping
109 actionMap.put("MOVE_RIGHT", new MoveXAction(1));
110 actionMap.put("MOVE_LEFT", new MoveXAction(-1));
111 actionMap.put("MOVE_UP", new MoveYAction(-1));
112 actionMap.put("MOVE_DOWN", new MoveYAction(1));
113 actionMap.put("STOP_MOVE_HORIZONTALLY", new MoveXAction(0));
114 actionMap.put("STOP_MOVE_VERTICALLY", new MoveYAction(0));
115 actionMap.put("ZOOM_IN", new ZoomInAction());
116 actionMap.put("ZOOM_OUT", new ZoomOutAction());
117 }
118
119 /**
120 * Start drawing the selection rectangle if it was the 1st button (left
121 * button)
122 */
123 @Override
124 public void mousePressed(MouseEvent e) {
125 if (e.getButton() == MouseEvent.BUTTON1) {
126 if (!iSizeButton.hit(e.getPoint())) {
127 iStartSelectionPoint = e.getPoint();
128 iEndSelectionPoint = e.getPoint();
129 }
130 }
131
132 }
133
134 @Override
135 public void mouseDragged(MouseEvent e) {
136 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) {
137 if (iStartSelectionPoint != null) {
138 iEndSelectionPoint = e.getPoint();
139 iSlippyMapChooser.setSelection(iStartSelectionPoint, iEndSelectionPoint);
140 isSelecting = true;
141 }
142 }
143 }
144
145 /**
146 * When dragging the map change the cursor back to it's pre-move cursor. If
147 * a double-click occurs center and zoom the map on the clicked location.
148 */
149 @Override
150 public void mouseReleased(MouseEvent e) {
151 if (e.getButton() == MouseEvent.BUTTON1) {
152
153 if (isSelecting && e.getClickCount() == 1) {
154 iSlippyMapChooser.setSelection(iStartSelectionPoint, e.getPoint());
155
156 // reset the selections start and end
157 iEndSelectionPoint = null;
158 iStartSelectionPoint = null;
159 isSelecting = false;
160
161 } else {
162 int sourceButton = iSourceButton.hit(e.getPoint());
163
164 if (iSizeButton.hit(e.getPoint())) {
165 iSizeButton.toggle();
166 iSlippyMapChooser.resizeSlippyMap();
167 } else if (iSlippyMapChooser.handleAttribution(e.getPoint(), true)) {
168 /* do nothing, handleAttribution() already did the work */
169 } else if (sourceButton == SourceButton.HIDE_OR_SHOW) {
170 iSourceButton.toggle();
171 iSlippyMapChooser.repaint();
172 } else if (sourceButton != 0) {
173 iSlippyMapChooser.toggleMapSource(iSourceButton.hitToTileSource(sourceButton));
174 }
175 }
176 }
177 }
178
179 @Override
180 public void mouseMoved(MouseEvent e) {
181 iSlippyMapChooser.handleAttribution(e.getPoint(), false);
182 }
183
184 private class MoveXAction extends AbstractAction {
185
186 int direction;
187
188 public MoveXAction(int direction) {
189 this.direction = direction;
190 }
191
192 public void actionPerformed(ActionEvent e) {
193 moveTask.setDirectionX(direction);
194 }
195 }
196
197 private class MoveYAction extends AbstractAction {
198
199 int direction;
200
201 public MoveYAction(int direction) {
202 this.direction = direction;
203 }
204
205 public void actionPerformed(ActionEvent e) {
206 moveTask.setDirectionY(direction);
207 }
208 }
209
210 /** Moves the map depending on which cursor keys are pressed (or not) */
211 private class MoveTask extends TimerTask {
212 /** The current x speed (pixels per timer interval) */
213 private double speedX = 1;
214
215 /** The current y speed (pixels per timer interval) */
216 private double speedY = 1;
217
218 /** The horizontal direction of movement, -1:left, 0:stop, 1:right */
219 private int directionX = 0;
220
221 /** The vertical direction of movement, -1:up, 0:stop, 1:down */
222 private int directionY = 0;
223
224 /**
225 * Indicated if <code>moveTask</code> is currently enabled (periodically
226 * executed via timer) or disabled
227 */
228 protected boolean scheduled = false;
229
230 protected void setDirectionX(int directionX) {
231 this.directionX = directionX;
232 updateScheduleStatus();
233 }
234
235 protected void setDirectionY(int directionY) {
236 this.directionY = directionY;
237 updateScheduleStatus();
238 }
239
240 private void updateScheduleStatus() {
241 boolean newMoveTaskState = !(directionX == 0 && directionY == 0);
242
243 if (newMoveTaskState != scheduled) {
244 scheduled = newMoveTaskState;
245 if (newMoveTaskState) {
246 timer.schedule(this, 0, timerInterval);
247 } else {
248 // We have to create a new instance because rescheduling a
249 // once canceled TimerTask is not possible
250 moveTask = new MoveTask();
251 cancel(); // Stop this TimerTask
252 }
253 }
254 }
255
256 @Override
257 public void run() {
258 // update the x speed
259 switch (directionX) {
260 case -1:
261 if (speedX > -1) {
262 speedX = -1;
263 }
264 if (speedX > -1 * MAX_SPEED) {
265 speedX -= ACCELERATION;
266 }
267 break;
268 case 0:
269 speedX = 0;
270 break;
271 case 1:
272 if (speedX < 1) {
273 speedX = 1;
274 }
275 if (speedX < MAX_SPEED) {
276 speedX += ACCELERATION;
277 }
278 break;
279 }
280
281 // update the y speed
282 switch (directionY) {
283 case -1:
284 if (speedY > -1) {
285 speedY = -1;
286 }
287 if (speedY > -1 * MAX_SPEED) {
288 speedY -= ACCELERATION;
289 }
290 break;
291 case 0:
292 speedY = 0;
293 break;
294 case 1:
295 if (speedY < 1) {
296 speedY = 1;
297 }
298 if (speedY < MAX_SPEED) {
299 speedY += ACCELERATION;
300 }
301 break;
302 }
303
304 // move the map
305 int moveX = (int) Math.floor(speedX);
306 int moveY = (int) Math.floor(speedY);
307 if (moveX != 0 || moveY != 0) {
308 iSlippyMapChooser.moveMap(moveX, moveY);
309 }
310 }
311 }
312
313 private class ZoomInAction extends AbstractAction {
314
315 public void actionPerformed(ActionEvent e) {
316 iSlippyMapChooser.zoomIn();
317 }
318 }
319
320 private class ZoomOutAction extends AbstractAction {
321
322 public void actionPerformed(ActionEvent e) {
323 iSlippyMapChooser.zoomOut();
324 }
325 }
326}
Note: See TracBrowser for help on using the repository browser.