source: josm/src/org/openstreetmap/josm/gui/SelectionManager.java@ 4

Last change on this file since 4 was 4, checked in by imi, 20 years ago

improved selection

File size: 6.8 KB
Line 
1package org.openstreetmap.josm.gui;
2
3import java.awt.Color;
4import java.awt.Component;
5import java.awt.Graphics;
6import java.awt.Point;
7import java.awt.Rectangle;
8import java.awt.event.InputEvent;
9import java.awt.event.MouseEvent;
10import java.awt.event.MouseListener;
11import java.awt.event.MouseMotionListener;
12
13/**
14 * Manages the selection of a rectangle. Listening to left and right mouse button
15 * presses and to mouse motions and draw the rectangle accordingly.
16 *
17 * Left mouse button selects a rectangle from the press until release. Pressing
18 * right mouse button while left is still pressed enable the rectangle to move
19 * around. Releasing the left button fires an action event to the listener given
20 * at constructor, except if the right is still pressed, which just remove the
21 * selection rectangle and does nothing.
22 *
23 * The point where the left mouse button was pressed and the current mouse
24 * position are two opposite corners of the selection rectangle.
25 *
26 * It is possible to specify an aspect ratio (width per height) which the
27 * selection rectangle always must have. In this case, the selection rectangle
28 * will be the largest window with this aspect ratio, where the position the left
29 * mouse button was pressed and the corner of the current mouse position are at
30 * opposite sites (the mouse position corner is the corner nearest to the mouse
31 * cursor).
32 *
33 * When the left mouse button was released, an ActionEvent is send to the
34 * ActionListener given at constructor. The source of this event is this manager.
35 *
36 * @author imi
37 */
38public class SelectionManager implements MouseListener, MouseMotionListener {
39
40 /**
41 * This is the interface that an user of SelectionManager has to implement
42 * to get informed when a selection closes.
43 * @author imi
44 */
45 public interface SelectionEnded {
46 /**
47 * Called, when the left mouse button was released.
48 * @param r The rectangle, that is currently the selection.
49 * @param modifiers The modifiers returned from the MouseEvent when
50 * the left mouse button was released.
51 * @see InputEvent#getModifiersEx()
52 */
53 public void selectionEnded(Rectangle r, int modifiers);
54 }
55 /**
56 * The listener that receives the events after left mouse button is released.
57 */
58 private final SelectionEnded selectionEndedListener;
59 /**
60 * Position of the map when the mouse button was pressed.
61 * If this is not <code>null</code>, a rectangle is drawn on screen.
62 */
63 private Point mousePosStart;
64 /**
65 * Position of the map when the selection rectangle was last drawn.
66 */
67 private Point mousePos;
68 /**
69 * The component, the selection rectangle is drawn onto.
70 */
71 private final Component drawComponent;
72 /**
73 * Whether the selection rectangle must obtain the aspect ratio of the
74 * drawComponent.
75 */
76 private boolean aspectRatio;
77
78 /**
79 * Create a new SelectionManager.
80 *
81 * @param actionListener The action listener that receives the event when
82 * the left button is released.
83 * @param aspectRatio If true, the selection window must obtain the aspect
84 * ratio of the drawComponent.
85 * @param drawComponent The component, the rectangle is drawn onto.
86 */
87 public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, Component drawComponent) {
88 this.selectionEndedListener = selectionEndedListener;
89 this.aspectRatio = aspectRatio;
90 this.drawComponent = drawComponent;
91 }
92
93 /**
94 * Register itself at the given event source.
95 * @param eventSource The emitter of the mouse events.
96 */
97 public void register(Component eventSource) {
98 eventSource.addMouseListener(this);
99 eventSource.addMouseMotionListener(this);
100 }
101 /**
102 * Unregister itself from the given event source. If a selection rectangle is
103 * shown, hide it first.
104 *
105 * @param eventSource The emitter of the mouse events.
106 */
107 public void unregister(Component eventSource) {
108 eventSource.removeMouseListener(this);
109 eventSource.removeMouseMotionListener(this);
110 }
111
112 /**
113 * If the correct button, start the "drawing rectangle" mode
114 */
115 public void mousePressed(MouseEvent e) {
116 if (e.getButton() == MouseEvent.BUTTON1) {
117 mousePosStart = e.getPoint();
118 mousePos = e.getPoint();
119 paintRect();
120 }
121 }
122
123 /**
124 * If the correct button is hold, draw the rectangle.
125 */
126 public void mouseDragged(MouseEvent e) {
127 int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK);
128
129 if (buttonPressed != 0) {
130 if (mousePosStart == null) {
131 mousePosStart = e.getPoint();
132 mousePos = e.getPoint();
133 paintRect();
134 }
135 paintRect();
136 }
137
138 if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
139 mousePos = e.getPoint();
140 paintRect();
141 } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
142 mousePosStart.x += e.getX()-mousePos.x;
143 mousePosStart.y += e.getY()-mousePos.y;
144 mousePos = e.getPoint();
145 paintRect();
146 }
147 }
148
149 /**
150 * Check the state of the keys and buttons and set the selection accordingly.
151 */
152 public void mouseReleased(MouseEvent e) {
153 if (e.getButton() != MouseEvent.BUTTON1)
154 return;
155 // disable the selection rect
156 paintRect();
157 Rectangle r = getSelectionRectangle();
158 mousePosStart = null;
159 mousePos = null;
160 if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
161 selectionEndedListener.selectionEnded(r, e.getModifiersEx());
162 }
163
164
165 /**
166 * Draw a selection rectangle on screen. If already a rectangle is drawn,
167 * it is removed instead.
168 */
169 private void paintRect() {
170 Graphics g = drawComponent.getGraphics();
171 g.setColor(Color.BLACK);
172 g.setXORMode(Color.WHITE);
173
174 Rectangle r = getSelectionRectangle();
175 g.drawRect(r.x,r.y,r.width,r.height);
176 }
177
178 /**
179 * Calculate and return the current selection rectangle
180 * @return A rectangle that spans from mousePos to mouseStartPos
181 */
182 private Rectangle getSelectionRectangle() {
183 int x = mousePosStart.x;
184 int y = mousePosStart.y;
185 int w = mousePos.x - mousePosStart.x;
186 int h = mousePos.y - mousePosStart.y;
187 if (w < 0) {
188 x += w;
189 w = -w;
190 }
191 if (h < 0) {
192 y += h;
193 h = -h;
194 }
195
196 if (aspectRatio) {
197 // keep the aspect ration by shrinking the rectangle
198 double aspectRatio = (double)drawComponent.getWidth()/drawComponent.getHeight();
199 if ((double)w/h > aspectRatio) {
200 int neww = (int)(h*aspectRatio);
201 if (mousePos.x < mousePosStart.x)
202 x += w-neww;
203 w = neww;
204 } else {
205 int newh = (int)(w/aspectRatio);
206 if (mousePos.y < mousePosStart.y)
207 y += h-newh;
208 h = newh;
209 }
210 }
211
212 return new Rectangle(x,y,w,h);
213 }
214
215 /**
216 * Does nothing. Only to satisfy MouseListener
217 */
218 public void mouseClicked(MouseEvent e) {}
219 /**
220 * Does nothing. Only to satisfy MouseListener
221 */
222 public void mouseEntered(MouseEvent e) {}
223 /**
224 * Does nothing. Only to satisfy MouseListener
225 */
226 public void mouseExited(MouseEvent e) {}
227 /**
228 * Does nothing. Only to satisfy MouseMotionListener
229 */
230 public void mouseMoved(MouseEvent e) {}
231}
Note: See TracBrowser for help on using the repository browser.