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

Last change on this file since 13265 was 12537, checked in by Don-vip, 7 years ago

PMD - VariableNamingConventions

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.bbox;
3
4import java.awt.Point;
5import java.awt.event.ActionEvent;
6import java.awt.event.InputEvent;
7import java.awt.event.KeyEvent;
8import java.awt.event.MouseAdapter;
9import java.awt.event.MouseEvent;
10import java.util.Timer;
11import java.util.TimerTask;
12
13import javax.swing.AbstractAction;
14import javax.swing.ActionMap;
15import javax.swing.InputMap;
16import javax.swing.JComponent;
17import javax.swing.JPanel;
18import javax.swing.KeyStroke;
19
20import org.openstreetmap.josm.Main;
21
22/**
23 * This class controls the user input by listening to mouse and key events.
24 * Currently implemented is: - zooming in and out with scrollwheel - zooming in
25 * and centering by double clicking - selecting an area by clicking and dragging
26 * the mouse
27 *
28 * @author Tim Haussmann
29 */
30public class SlippyMapControler extends MouseAdapter {
31
32 /** A Timer for smoothly moving the map area */
33 private static final Timer TIMER = new Timer(true);
34
35 /** Does the moving */
36 private MoveTask moveTask = new MoveTask();
37
38 /** How often to do the moving (milliseconds) */
39 private static long timerInterval = 20;
40
41 /** The maximum speed (pixels per timer interval) */
42 private static final double MAX_SPEED = 20;
43
44 /** The speed increase per timer interval when a cursor button is clicked */
45 private static final double ACCELERATION = 0.10;
46
47 private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK;
48
49 private static final String[] N = {
50 ",", ".", "up", "right", "down", "left"};
51 private static final int[] K = {
52 KeyEvent.VK_COMMA, KeyEvent.VK_PERIOD, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT};
53
54 // start and end point of selection rectangle
55 private Point iStartSelectionPoint;
56 private Point iEndSelectionPoint;
57
58 private final SlippyMapBBoxChooser iSlippyMapChooser;
59
60 private boolean isSelecting;
61
62 /**
63 * Constructs a new {@code SlippyMapControler}.
64 * @param navComp navigatable component
65 * @param contentPane content pane
66 */
67 public SlippyMapControler(SlippyMapBBoxChooser navComp, JPanel contentPane) {
68 iSlippyMapChooser = navComp;
69 iSlippyMapChooser.addMouseListener(this);
70 iSlippyMapChooser.addMouseMotionListener(this);
71
72 if (contentPane != null) {
73 for (int i = 0; i < N.length; ++i) {
74 contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
75 KeyStroke.getKeyStroke(K[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer." + N[i]);
76 }
77 }
78 isSelecting = false;
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_ADD, 0, false), "ZOOM_IN");
99 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0, false), "ZOOM_IN");
100 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0, false), "ZOOM_IN");
101 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.SHIFT_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 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0, false), "ZOOM_OUT");
106 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 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 button)
121 */
122 @Override
123 public void mousePressed(MouseEvent e) {
124 if (e.getButton() == MouseEvent.BUTTON1 && !(Main.isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) {
125 iStartSelectionPoint = e.getPoint();
126 iEndSelectionPoint = e.getPoint();
127 }
128 }
129
130 @Override
131 public void mouseDragged(MouseEvent e) {
132 if (iStartSelectionPoint != null && (e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK
133 && !(Main.isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) {
134 iEndSelectionPoint = e.getPoint();
135 iSlippyMapChooser.setSelection(iStartSelectionPoint, iEndSelectionPoint);
136 isSelecting = true;
137 }
138 }
139
140 /**
141 * When dragging the map change the cursor back to it's pre-move cursor. If
142 * a double-click occurs center and zoom the map on the clicked location.
143 */
144 @Override
145 public void mouseReleased(MouseEvent e) {
146 if (e.getButton() == MouseEvent.BUTTON1) {
147
148 if (isSelecting && e.getClickCount() == 1) {
149 iSlippyMapChooser.setSelection(iStartSelectionPoint, e.getPoint());
150
151 // reset the selections start and end
152 iEndSelectionPoint = null;
153 iStartSelectionPoint = null;
154 isSelecting = false;
155
156 } else {
157 iSlippyMapChooser.handleAttribution(e.getPoint(), true);
158 }
159 }
160 }
161
162 @Override
163 public void mouseMoved(MouseEvent e) {
164 iSlippyMapChooser.handleAttribution(e.getPoint(), false);
165 }
166
167 private class MoveXAction extends AbstractAction {
168
169 private final int direction;
170
171 MoveXAction(int direction) {
172 this.direction = direction;
173 }
174
175 @Override
176 public void actionPerformed(ActionEvent e) {
177 moveTask.setDirectionX(direction);
178 }
179 }
180
181 private class MoveYAction extends AbstractAction {
182
183 private final int direction;
184
185 MoveYAction(int direction) {
186 this.direction = direction;
187 }
188
189 @Override
190 public void actionPerformed(ActionEvent e) {
191 moveTask.setDirectionY(direction);
192 }
193 }
194
195 /** Moves the map depending on which cursor keys are pressed (or not) */
196 private class MoveTask extends TimerTask {
197 /** The current x speed (pixels per timer interval) */
198 private double speedX = 1;
199
200 /** The current y speed (pixels per timer interval) */
201 private double speedY = 1;
202
203 /** The horizontal direction of movement, -1:left, 0:stop, 1:right */
204 private int directionX;
205
206 /** The vertical direction of movement, -1:up, 0:stop, 1:down */
207 private int directionY;
208
209 /**
210 * Indicated if <code>moveTask</code> is currently enabled (periodically
211 * executed via timer) or disabled
212 */
213 protected boolean scheduled;
214
215 protected void setDirectionX(int directionX) {
216 this.directionX = directionX;
217 updateScheduleStatus();
218 }
219
220 protected void setDirectionY(int directionY) {
221 this.directionY = directionY;
222 updateScheduleStatus();
223 }
224
225 private void updateScheduleStatus() {
226 boolean newMoveTaskState = !(directionX == 0 && directionY == 0);
227
228 if (newMoveTaskState != scheduled) {
229 scheduled = newMoveTaskState;
230 if (newMoveTaskState) {
231 TIMER.schedule(this, 0, timerInterval);
232 } else {
233 // We have to create a new instance because rescheduling a
234 // once canceled TimerTask is not possible
235 moveTask = new MoveTask();
236 cancel(); // Stop this TimerTask
237 }
238 }
239 }
240
241 @Override
242 public void run() {
243 // update the x speed
244 switch (directionX) {
245 case -1:
246 if (speedX > -1) {
247 speedX = -1;
248 }
249 if (speedX > -1 * MAX_SPEED) {
250 speedX -= ACCELERATION;
251 }
252 break;
253 case 0:
254 speedX = 0;
255 break;
256 case 1:
257 if (speedX < 1) {
258 speedX = 1;
259 }
260 if (speedX < MAX_SPEED) {
261 speedX += ACCELERATION;
262 }
263 break;
264 default:
265 throw new IllegalStateException(Integer.toString(directionX));
266 }
267
268 // update the y speed
269 switch (directionY) {
270 case -1:
271 if (speedY > -1) {
272 speedY = -1;
273 }
274 if (speedY > -1 * MAX_SPEED) {
275 speedY -= ACCELERATION;
276 }
277 break;
278 case 0:
279 speedY = 0;
280 break;
281 case 1:
282 if (speedY < 1) {
283 speedY = 1;
284 }
285 if (speedY < MAX_SPEED) {
286 speedY += ACCELERATION;
287 }
288 break;
289 default:
290 throw new IllegalStateException(Integer.toString(directionY));
291 }
292
293 // move the map
294 int moveX = (int) Math.floor(speedX);
295 int moveY = (int) Math.floor(speedY);
296 if (moveX != 0 || moveY != 0) {
297 iSlippyMapChooser.moveMap(moveX, moveY);
298 }
299 }
300 }
301
302 private class ZoomInAction extends AbstractAction {
303
304 @Override
305 public void actionPerformed(ActionEvent e) {
306 iSlippyMapChooser.zoomIn();
307 }
308 }
309
310 private class ZoomOutAction extends AbstractAction {
311
312 @Override
313 public void actionPerformed(ActionEvent e) {
314 iSlippyMapChooser.zoomOut();
315 }
316 }
317}
Note: See TracBrowser for help on using the repository browser.