| 1 | // License: GPL. Copyright 2007 by Christian Gallioz (aka khris78) |
|---|
| 2 | |
|---|
| 3 | package org.openstreetmap.josm.gui; |
|---|
| 4 | |
|---|
| 5 | import java.awt.BorderLayout; |
|---|
| 6 | import java.awt.Dimension; |
|---|
| 7 | import java.awt.Point; |
|---|
| 8 | import java.awt.Rectangle; |
|---|
| 9 | import java.awt.event.ActionEvent; |
|---|
| 10 | import java.awt.event.ActionListener; |
|---|
| 11 | import java.awt.event.ComponentAdapter; |
|---|
| 12 | import java.awt.event.ComponentEvent; |
|---|
| 13 | import java.awt.event.MouseAdapter; |
|---|
| 14 | import java.awt.event.MouseEvent; |
|---|
| 15 | import java.util.ArrayList; |
|---|
| 16 | import java.util.List; |
|---|
| 17 | |
|---|
| 18 | import javax.swing.JButton; |
|---|
| 19 | import javax.swing.JComponent; |
|---|
| 20 | import javax.swing.JPanel; |
|---|
| 21 | import javax.swing.JViewport; |
|---|
| 22 | import javax.swing.Timer; |
|---|
| 23 | |
|---|
| 24 | import org.openstreetmap.josm.tools.ImageProvider; |
|---|
| 25 | |
|---|
| 26 | /** A viewport with UP and DOWN arrow buttons, so that the user can make the |
|---|
| 27 | * content scroll. |
|---|
| 28 | */ |
|---|
| 29 | public class ScrollViewport extends JPanel { |
|---|
| 30 | |
|---|
| 31 | private static final int NO_SCROLL = 0; |
|---|
| 32 | |
|---|
| 33 | public static final int UP_DIRECTION = 1; |
|---|
| 34 | public static final int DOWN_DIRECTION = 2; |
|---|
| 35 | public static final int LEFT_DIRECTION = 4; |
|---|
| 36 | public static final int RIGHT_DIRECTION = 8; |
|---|
| 37 | public static final int VERTICAL_DIRECTION = UP_DIRECTION | DOWN_DIRECTION; |
|---|
| 38 | public static final int HORIZONTAL_DIRECTION = LEFT_DIRECTION | RIGHT_DIRECTION; |
|---|
| 39 | public static final int ALL_DIRECTION = HORIZONTAL_DIRECTION | VERTICAL_DIRECTION; |
|---|
| 40 | |
|---|
| 41 | private class ScrollViewPortMouseListener extends MouseAdapter { |
|---|
| 42 | private int direction; |
|---|
| 43 | |
|---|
| 44 | public ScrollViewPortMouseListener(int direction) { |
|---|
| 45 | this.direction = direction; |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | @Override public void mouseExited(MouseEvent arg0) { |
|---|
| 49 | ScrollViewport.this.scrollDirection = NO_SCROLL; |
|---|
| 50 | timer.stop(); |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | @Override public void mouseReleased(MouseEvent arg0) { |
|---|
| 54 | ScrollViewport.this.scrollDirection = NO_SCROLL; |
|---|
| 55 | timer.stop(); |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | @Override public void mousePressed(MouseEvent arg0) { |
|---|
| 59 | ScrollViewport.this.scrollDirection = direction; |
|---|
| 60 | scroll(); |
|---|
| 61 | timer.restart(); |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | private JViewport vp = new JViewport(); |
|---|
| 67 | private JComponent component = null; |
|---|
| 68 | |
|---|
| 69 | private List<JButton> buttons = new ArrayList<JButton>(); |
|---|
| 70 | |
|---|
| 71 | private Timer timer = new Timer(100, new ActionListener() { |
|---|
| 72 | public void actionPerformed(ActionEvent arg0) { |
|---|
| 73 | ScrollViewport.this.scroll(); |
|---|
| 74 | } |
|---|
| 75 | }); |
|---|
| 76 | |
|---|
| 77 | private int scrollDirection = NO_SCROLL; |
|---|
| 78 | |
|---|
| 79 | public ScrollViewport(JComponent c, int direction) { |
|---|
| 80 | this(direction); |
|---|
| 81 | add(c); |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | public ScrollViewport(int direction) { |
|---|
| 85 | setLayout(new BorderLayout()); |
|---|
| 86 | |
|---|
| 87 | JButton button; |
|---|
| 88 | |
|---|
| 89 | // UP |
|---|
| 90 | if ((direction & UP_DIRECTION) > 0) { |
|---|
| 91 | button = new JButton(); |
|---|
| 92 | button.addMouseListener(new ScrollViewPortMouseListener(UP_DIRECTION)); |
|---|
| 93 | button.setPreferredSize(new Dimension(10,10)); |
|---|
| 94 | button.setIcon(ImageProvider.get("svpUp")); |
|---|
| 95 | add(button, BorderLayout.NORTH); |
|---|
| 96 | buttons.add(button); |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | // DOWN |
|---|
| 100 | if ((direction & DOWN_DIRECTION) > 0) { |
|---|
| 101 | button = new JButton(); |
|---|
| 102 | button.addMouseListener(new ScrollViewPortMouseListener(DOWN_DIRECTION)); |
|---|
| 103 | button.setPreferredSize(new Dimension(10,10)); |
|---|
| 104 | button.setIcon(ImageProvider.get("svpDown")); |
|---|
| 105 | add(button, BorderLayout.SOUTH); |
|---|
| 106 | buttons.add(button); |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | // LEFT |
|---|
| 110 | if ((direction & LEFT_DIRECTION) > 0) { |
|---|
| 111 | button = new JButton(); |
|---|
| 112 | button.addMouseListener(new ScrollViewPortMouseListener(LEFT_DIRECTION)); |
|---|
| 113 | button.setPreferredSize(new Dimension(10,10)); |
|---|
| 114 | button.setIcon(ImageProvider.get("svpLeft")); |
|---|
| 115 | add(button, BorderLayout.WEST); |
|---|
| 116 | buttons.add(button); |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | // RIGHT |
|---|
| 120 | if ((direction & RIGHT_DIRECTION) > 0) { |
|---|
| 121 | button = new JButton(); |
|---|
| 122 | button.addMouseListener(new ScrollViewPortMouseListener(RIGHT_DIRECTION)); |
|---|
| 123 | button.setPreferredSize(new Dimension(10,10)); |
|---|
| 124 | button.setIcon(ImageProvider.get("svpRight")); |
|---|
| 125 | add(button, BorderLayout.EAST); |
|---|
| 126 | buttons.add(button); |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | add(vp, BorderLayout.CENTER); |
|---|
| 130 | |
|---|
| 131 | this.addComponentListener(new ComponentAdapter() { |
|---|
| 132 | @Override public void componentResized(ComponentEvent e) { |
|---|
| 133 | showOrHideButtons(); |
|---|
| 134 | } |
|---|
| 135 | }); |
|---|
| 136 | |
|---|
| 137 | showOrHideButtons(); |
|---|
| 138 | |
|---|
| 139 | timer.setRepeats(true); |
|---|
| 140 | timer.setInitialDelay(400); |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | public synchronized void scroll() { |
|---|
| 144 | int direction = scrollDirection; |
|---|
| 145 | |
|---|
| 146 | if (component == null || direction == NO_SCROLL) |
|---|
| 147 | return; |
|---|
| 148 | |
|---|
| 149 | Rectangle viewRect = vp.getViewRect(); |
|---|
| 150 | |
|---|
| 151 | int deltaX = 0; |
|---|
| 152 | int deltaY = 0; |
|---|
| 153 | |
|---|
| 154 | if (direction < LEFT_DIRECTION) { |
|---|
| 155 | deltaY = viewRect.height * 2 / 7; |
|---|
| 156 | } else { |
|---|
| 157 | deltaX = viewRect.width * 2 / 7; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | switch (direction) { |
|---|
| 161 | case UP_DIRECTION : |
|---|
| 162 | deltaY *= -1; |
|---|
| 163 | break; |
|---|
| 164 | case LEFT_DIRECTION : |
|---|
| 165 | deltaX *= -1; |
|---|
| 166 | break; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | scroll(deltaX, deltaY); |
|---|
| 170 | } |
|---|
| 171 | public synchronized void scroll(int deltaX, int deltaY) { |
|---|
| 172 | if (component == null) |
|---|
| 173 | return; |
|---|
| 174 | Dimension compSize = component.getSize(); |
|---|
| 175 | Rectangle viewRect = vp.getViewRect(); |
|---|
| 176 | |
|---|
| 177 | int newX = viewRect.x + deltaX; |
|---|
| 178 | int newY = viewRect.y + deltaY; |
|---|
| 179 | |
|---|
| 180 | if (newY < 0) { |
|---|
| 181 | newY = 0; |
|---|
| 182 | } |
|---|
| 183 | if (newY > compSize.height - viewRect.height) { |
|---|
| 184 | newY = compSize.height - viewRect.height; |
|---|
| 185 | } |
|---|
| 186 | if (newX < 0) { |
|---|
| 187 | newX = 0; |
|---|
| 188 | } |
|---|
| 189 | if (newX > compSize.width - viewRect.width) { |
|---|
| 190 | newX = compSize.width - viewRect.width; |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | vp.setViewPosition(new Point(newX, newY)); |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | /** |
|---|
| 197 | * Update the visibility of the buttons |
|---|
| 198 | * Only show them if the Viewport is too small for the content. |
|---|
| 199 | */ |
|---|
| 200 | public void showOrHideButtons() { |
|---|
| 201 | boolean needButtons = vp.getViewSize().height > vp.getViewRect().height || |
|---|
| 202 | vp.getViewSize().width > vp.getViewRect().width; |
|---|
| 203 | for (JButton b : buttons) { |
|---|
| 204 | b.setVisible(needButtons); |
|---|
| 205 | } |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | public Rectangle getViewRect() { |
|---|
| 209 | return vp.getViewRect(); |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | public Dimension getViewSize() { |
|---|
| 213 | return vp.getViewSize(); |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | public Point getViewPosition() { |
|---|
| 217 | return vp.getViewPosition(); |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | public void add(JComponent c) { |
|---|
| 221 | vp.removeAll(); |
|---|
| 222 | this.component = c; |
|---|
| 223 | vp.add(c); |
|---|
| 224 | } |
|---|
| 225 | } |
|---|