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

Last change on this file since 4077 was 3720, checked in by bastiK, 13 years ago

added missing svn:eol-style

  • Property svn:eol-style set to native
File size: 10.9 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 /**
60 * Create a new OsmMapControl
61 */
62 public SlippyMapControler(SlippyMapBBoxChooser navComp, JPanel contentPane, SizeButton sizeButton, SourceButton sourceButton) {
63 this.iSlippyMapChooser = navComp;
64 iSlippyMapChooser.addMouseListener(this);
65 iSlippyMapChooser.addMouseMotionListener(this);
66
67 String[] n = { ",", ".", "up", "right", "down", "left" };
68 int[] k = { KeyEvent.VK_COMMA, KeyEvent.VK_PERIOD, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN,
69 KeyEvent.VK_LEFT };
70
71 if (contentPane != null) {
72 for (int i = 0; i < n.length; ++i) {
73 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
74 KeyStroke.getKeyStroke(k[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer." + n[i]);
75 }
76 }
77 iSizeButton = sizeButton;
78 iSourceButton = sourceButton;
79
80 InputMap inputMap = navComp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
81 ActionMap actionMap = navComp.getActionMap();
82
83 // map moving
84 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "MOVE_RIGHT");
85 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "MOVE_LEFT");
86 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "MOVE_UP");
87 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "MOVE_DOWN");
88 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "STOP_MOVE_HORIZONTALLY");
89 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "STOP_MOVE_HORIZONTALLY");
90 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "STOP_MOVE_VERTICALLY");
91 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "STOP_MOVE_VERTICALLY");
92
93 // zooming. To avoid confusion about which modifier key to use,
94 // we just add all keys left of the space bar
95 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK, false), "ZOOM_IN");
96 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.META_DOWN_MASK, false), "ZOOM_IN");
97 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK, false), "ZOOM_IN");
98 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK, false), "ZOOM_OUT");
99 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.META_DOWN_MASK, false), "ZOOM_OUT");
100 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK, false), "ZOOM_OUT");
101
102 // action mapping
103 actionMap.put("MOVE_RIGHT", new MoveXAction(1));
104 actionMap.put("MOVE_LEFT", new MoveXAction(-1));
105 actionMap.put("MOVE_UP", new MoveYAction(-1));
106 actionMap.put("MOVE_DOWN", new MoveYAction(1));
107 actionMap.put("STOP_MOVE_HORIZONTALLY", new MoveXAction(0));
108 actionMap.put("STOP_MOVE_VERTICALLY", new MoveYAction(0));
109 actionMap.put("ZOOM_IN", new ZoomInAction());
110 actionMap.put("ZOOM_OUT", new ZoomOutAction());
111 }
112
113 /**
114 * Start drawing the selection rectangle if it was the 1st button (left
115 * button)
116 */
117 @Override
118 public void mousePressed(MouseEvent e) {
119 if (e.getButton() == MouseEvent.BUTTON1) {
120 if (!iSizeButton.hit(e.getPoint())) {
121 iStartSelectionPoint = e.getPoint();
122 iEndSelectionPoint = e.getPoint();
123 }
124 }
125
126 }
127
128 @Override
129 public void mouseDragged(MouseEvent e) {
130 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) {
131 if (iStartSelectionPoint != null) {
132 iEndSelectionPoint = e.getPoint();
133 iSlippyMapChooser.setSelection(iStartSelectionPoint, iEndSelectionPoint);
134 }
135 }
136 }
137
138 /**
139 * When dragging the map change the cursor back to it's pre-move cursor. If
140 * a double-click occurs center and zoom the map on the clicked location.
141 */
142 @Override
143 public void mouseReleased(MouseEvent e) {
144 if (e.getButton() == MouseEvent.BUTTON1) {
145
146 int sourceButton = iSourceButton.hit(e.getPoint());
147
148 if (iSizeButton.hit(e.getPoint())) {
149 iSizeButton.toggle();
150 iSlippyMapChooser.resizeSlippyMap();
151 } else if (sourceButton == SourceButton.HIDE_OR_SHOW) {
152 iSourceButton.toggle();
153 iSlippyMapChooser.repaint();
154
155 } else if (sourceButton != 0) {
156 iSlippyMapChooser.toggleMapSource(iSourceButton.hitToTileSource(sourceButton));
157 } else {
158 if (e.getClickCount() == 1) {
159 iSlippyMapChooser.setSelection(iStartSelectionPoint, e.getPoint());
160
161 // reset the selections start and end
162 iEndSelectionPoint = null;
163 iStartSelectionPoint = null;
164 }
165 }
166
167 }
168 }
169
170 @Override
171 public void mouseMoved(MouseEvent e) {
172 }
173
174 private class MoveXAction extends AbstractAction {
175
176 int direction;
177
178 public MoveXAction(int direction) {
179 this.direction = direction;
180 }
181
182 public void actionPerformed(ActionEvent e) {
183 moveTask.setDirectionX(direction);
184 }
185 }
186
187 private class MoveYAction extends AbstractAction {
188
189 int direction;
190
191 public MoveYAction(int direction) {
192 this.direction = direction;
193 }
194
195 public void actionPerformed(ActionEvent e) {
196 moveTask.setDirectionY(direction);
197 }
198 }
199
200 /** Moves the map depending on which cursor keys are pressed (or not) */
201 private class MoveTask extends TimerTask {
202 /** The current x speed (pixels per timer interval) */
203 private double speedX = 1;
204
205 /** The current y speed (pixels per timer interval) */
206 private double speedY = 1;
207
208 /** The horizontal direction of movement, -1:left, 0:stop, 1:right */
209 private int directionX = 0;
210
211 /** The vertical direction of movement, -1:up, 0:stop, 1:down */
212 private int directionY = 0;
213
214 /**
215 * Indicated if <code>moveTask</code> is currently enabled (periodically
216 * executed via timer) or disabled
217 */
218 protected boolean scheduled = false;
219
220 protected void setDirectionX(int directionX) {
221 this.directionX = directionX;
222 updateScheduleStatus();
223 }
224
225 protected void setDirectionY(int directionY) {
226 this.directionY = directionY;
227 updateScheduleStatus();
228 }
229
230 private void updateScheduleStatus() {
231 boolean newMoveTaskState = !(directionX == 0 && directionY == 0);
232
233 if (newMoveTaskState != scheduled) {
234 scheduled = newMoveTaskState;
235 if (newMoveTaskState) {
236 timer.schedule(this, 0, timerInterval);
237 } else {
238 // We have to create a new instance because rescheduling a
239 // once canceled TimerTask is not possible
240 moveTask = new MoveTask();
241 cancel(); // Stop this TimerTask
242 }
243 }
244 }
245
246 @Override
247 public void run() {
248 // update the x speed
249 switch (directionX) {
250 case -1:
251 if (speedX > -1) {
252 speedX = -1;
253 }
254 if (speedX > -1 * MAX_SPEED) {
255 speedX -= ACCELERATION;
256 }
257 break;
258 case 0:
259 speedX = 0;
260 break;
261 case 1:
262 if (speedX < 1) {
263 speedX = 1;
264 }
265 if (speedX < MAX_SPEED) {
266 speedX += ACCELERATION;
267 }
268 break;
269 }
270
271 // update the y speed
272 switch (directionY) {
273 case -1:
274 if (speedY > -1) {
275 speedY = -1;
276 }
277 if (speedY > -1 * MAX_SPEED) {
278 speedY -= ACCELERATION;
279 }
280 break;
281 case 0:
282 speedY = 0;
283 break;
284 case 1:
285 if (speedY < 1) {
286 speedY = 1;
287 }
288 if (speedY < MAX_SPEED) {
289 speedY += ACCELERATION;
290 }
291 break;
292 }
293
294 // move the map
295 int moveX = (int) Math.floor(speedX);
296 int moveY = (int) Math.floor(speedY);
297 if (moveX != 0 || moveY != 0) {
298 iSlippyMapChooser.moveMap(moveX, moveY);
299 }
300 }
301 }
302
303 private class ZoomInAction extends AbstractAction {
304
305 public void actionPerformed(ActionEvent e) {
306 iSlippyMapChooser.zoomIn();
307 }
308 }
309
310 private class ZoomOutAction extends AbstractAction {
311
312 public void actionPerformed(ActionEvent e) {
313 iSlippyMapChooser.zoomOut();
314 }
315 }
316}
Note: See TracBrowser for help on using the repository browser.