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

Last change on this file since 4195 was 4195, checked in by stoecker, 13 years ago

fix slippy map attribution handling and allow bounds and attribution specification in maps specification (not exposed to user currently)

  • Property svn:eol-style set to native
File size: 11.1 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 (iSlippyMapChooser.handleAttribution(e.getPoint(), true)) {
152 /* do nothing, handleAttribution() already did the work */
153 } else if (sourceButton == SourceButton.HIDE_OR_SHOW) {
154 iSourceButton.toggle();
155 iSlippyMapChooser.repaint();
156 } else if (sourceButton != 0) {
157 iSlippyMapChooser.toggleMapSource(iSourceButton.hitToTileSource(sourceButton));
158 } else {
159 if (e.getClickCount() == 1) {
160 iSlippyMapChooser.setSelection(iStartSelectionPoint, e.getPoint());
161
162 // reset the selections start and end
163 iEndSelectionPoint = null;
164 iStartSelectionPoint = null;
165 }
166 }
167
168 }
169 }
170
171 @Override
172 public void mouseMoved(MouseEvent e) {
173 iSlippyMapChooser.handleAttribution(e.getPoint(), false);
174 }
175
176 private class MoveXAction extends AbstractAction {
177
178 int direction;
179
180 public MoveXAction(int direction) {
181 this.direction = direction;
182 }
183
184 public void actionPerformed(ActionEvent e) {
185 moveTask.setDirectionX(direction);
186 }
187 }
188
189 private class MoveYAction extends AbstractAction {
190
191 int direction;
192
193 public MoveYAction(int direction) {
194 this.direction = direction;
195 }
196
197 public void actionPerformed(ActionEvent e) {
198 moveTask.setDirectionY(direction);
199 }
200 }
201
202 /** Moves the map depending on which cursor keys are pressed (or not) */
203 private class MoveTask extends TimerTask {
204 /** The current x speed (pixels per timer interval) */
205 private double speedX = 1;
206
207 /** The current y speed (pixels per timer interval) */
208 private double speedY = 1;
209
210 /** The horizontal direction of movement, -1:left, 0:stop, 1:right */
211 private int directionX = 0;
212
213 /** The vertical direction of movement, -1:up, 0:stop, 1:down */
214 private int directionY = 0;
215
216 /**
217 * Indicated if <code>moveTask</code> is currently enabled (periodically
218 * executed via timer) or disabled
219 */
220 protected boolean scheduled = false;
221
222 protected void setDirectionX(int directionX) {
223 this.directionX = directionX;
224 updateScheduleStatus();
225 }
226
227 protected void setDirectionY(int directionY) {
228 this.directionY = directionY;
229 updateScheduleStatus();
230 }
231
232 private void updateScheduleStatus() {
233 boolean newMoveTaskState = !(directionX == 0 && directionY == 0);
234
235 if (newMoveTaskState != scheduled) {
236 scheduled = newMoveTaskState;
237 if (newMoveTaskState) {
238 timer.schedule(this, 0, timerInterval);
239 } else {
240 // We have to create a new instance because rescheduling a
241 // once canceled TimerTask is not possible
242 moveTask = new MoveTask();
243 cancel(); // Stop this TimerTask
244 }
245 }
246 }
247
248 @Override
249 public void run() {
250 // update the x speed
251 switch (directionX) {
252 case -1:
253 if (speedX > -1) {
254 speedX = -1;
255 }
256 if (speedX > -1 * MAX_SPEED) {
257 speedX -= ACCELERATION;
258 }
259 break;
260 case 0:
261 speedX = 0;
262 break;
263 case 1:
264 if (speedX < 1) {
265 speedX = 1;
266 }
267 if (speedX < MAX_SPEED) {
268 speedX += ACCELERATION;
269 }
270 break;
271 }
272
273 // update the y speed
274 switch (directionY) {
275 case -1:
276 if (speedY > -1) {
277 speedY = -1;
278 }
279 if (speedY > -1 * MAX_SPEED) {
280 speedY -= ACCELERATION;
281 }
282 break;
283 case 0:
284 speedY = 0;
285 break;
286 case 1:
287 if (speedY < 1) {
288 speedY = 1;
289 }
290 if (speedY < MAX_SPEED) {
291 speedY += ACCELERATION;
292 }
293 break;
294 }
295
296 // move the map
297 int moveX = (int) Math.floor(speedX);
298 int moveY = (int) Math.floor(speedY);
299 if (moveX != 0 || moveY != 0) {
300 iSlippyMapChooser.moveMap(moveX, moveY);
301 }
302 }
303 }
304
305 private class ZoomInAction extends AbstractAction {
306
307 public void actionPerformed(ActionEvent e) {
308 iSlippyMapChooser.zoomIn();
309 }
310 }
311
312 private class ZoomOutAction extends AbstractAction {
313
314 public void actionPerformed(ActionEvent e) {
315 iSlippyMapChooser.zoomOut();
316 }
317 }
318}
Note: See TracBrowser for help on using the repository browser.