Ticket #2205: SlippyMapKeyMovement.diff

File SlippyMapKeyMovement.diff, 17.1 KB (added by jpstotz, 15 years ago)
  • src/org/openstreetmap/josm/gui/download/OsmMapControl.java

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

     
    104104        slipyyMapTabPanel = new JPanel();
    105105        slipyyMapTabPanel.setLayout(new BorderLayout());
    106106        slipyyMapTabPanel.add(this, BorderLayout.CENTER);
    107         slipyyMapTabPanel.add(new JLabel((tr("Zoom: Mousewheel or double click.   "
    108                 + "Move map: Hold right mousebutton and move mouse.   Select: Click."))), BorderLayout.SOUTH);
     107        String labelText = "<b>Zoom:</b> Mousewheel, double click or Ctrl + Up/Down "
     108                + "<b>Move map:</b> Hold right mousebutton and move mouse or use cursor keys. <b>Select:</b> Click.";
     109        slipyyMapTabPanel.add(new JLabel("<html>" + tr(labelText) + "</html>"), BorderLayout.SOUTH);
    109110        iGui.tabpane.add(slipyyMapTabPanel, tr("Slippy map"));
    110111        new OsmMapControl(this, slipyyMapTabPanel, iSizeButton, iSourceButton);
    111112    }