• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2007 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); You may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
6 // applicable law or agreed to in writing, software distributed under the
7 // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
8 // OF ANY KIND, either express or implied. See the License for the specific
9 // language governing permissions and limitations under the License.
10 
11 package com.google.scrollview.events;
12 
13 import com.google.scrollview.ScrollView;
14 import com.google.scrollview.ui.SVWindow;
15 import com.google.scrollview.events.SVEvent;
16 import com.google.scrollview.events.SVEventType;
17 
18 import java.awt.Color;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ActionListener;
21 import java.awt.event.KeyEvent;
22 import java.awt.event.KeyListener;
23 import java.awt.event.WindowEvent;
24 import java.awt.event.WindowListener;
25 
26 import javax.swing.Timer;
27 
28 import edu.umd.cs.piccolo.PCamera;
29 import edu.umd.cs.piccolo.PNode;
30 import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
31 import edu.umd.cs.piccolo.event.PInputEvent;
32 import edu.umd.cs.piccolo.nodes.PPath;
33 
34 /**
35  * The ScrollViewEventHandler takes care of any events which might happen on the
36  * canvas and converts them to an according SVEvent, which is (using the
37  * processEvent method) then added to a message queue. All events from the
38  * message queue get sent gradually
39  *
40  * @author wanke@google.com
41  */
42 public class SVEventHandler extends PBasicInputEventHandler implements
43     ActionListener, KeyListener, WindowListener {
44 
45   /** Necessary to wait for a defined period of time (for SVET_HOVER). */
46   public Timer timer;
47 
48   /** The window which the event corresponds to. */
49   private SVWindow svWindow;
50 
51   /** These are used to determine a selection size (for SVET_SELECTION). */
52   private int lastX = 0;
53   private int lastY = 0;
54 
55   /**
56    * These are used in case we want to transmit our position, but do not get it
57    * because it was no MouseEvent, in particular SVET_HOVER and SVET_INPUT.
58    */
59   private int lastXMove = 0;
60   private int lastYMove = 0;
61 
62   /** For Drawing a rubber-band rectangle for selection */
63   private int startX = 0;
64   private int startY = 0;
65   private float rubberBandTransparency = 0.5f;
66   private PNode selection = null;
67 
68   /** The string entered since the last enter. Since the client
69    *  end eats all newlines, we can't use the newline
70    *  character, so use ! for now, as it cannot be entered
71    *  directly anyway and therefore can never show up for real. */
72   private String keyStr = "!";
73 
74   /** Setup the timer. */
SVEventHandler(SVWindow wdw)75   public SVEventHandler(SVWindow wdw) {
76     timer = new Timer(1000, this);
77     svWindow = wdw;
78   }
79 
80   /**
81    * Store the newest x,y values, add the message to the queue and restart the
82    * timer.
83    */
processEvent(SVEvent e)84   private void processEvent(SVEvent e) {
85     lastXMove = e.x;
86     lastYMove = e.y;
87     ScrollView.addMessage(e);
88     timer.restart();
89   }
90 
91   /** Show the associated popup menu at (x,y) (relative position of the window). */
showPopup(PInputEvent e)92   private void showPopup(PInputEvent e) {
93     double x = e.getCanvasPosition().getX();
94     double y = e.getCanvasPosition().getY();
95 
96     if (svWindow.svPuMenu != null) {
97       svWindow.svPuMenu.show(svWindow, (int) x, (int) y);
98     }
99   }
100 
101 
102   /** The mouse is clicked - create an SVET_CLICK event. */
103   @Override
mouseClicked(PInputEvent e)104   public void mouseClicked(PInputEvent e) {
105     if (e.isPopupTrigger()) {
106       showPopup(e);
107     } else {
108       processEvent(new SVEvent(SVEventType.SVET_CLICK, svWindow, (int) e
109           .getPosition().getX(), (int) e.getPosition().getY(), 0, 0, null));
110     }
111   }
112 
113   /**
114    * The mouse key is pressed (and keeps getting pressed).
115    * Depending on the OS, show a popup menu (if the button pressed is associated
116    * with popup menus, like the RMB under windows&linux) or otherwise save the
117    * position (in case it is a selection).
118    */
119   @Override
mousePressed(PInputEvent e)120   public void mousePressed(PInputEvent e) {
121     if (e.isPopupTrigger()) {
122       showPopup(e);
123     } else {
124       lastX = (int) e.getPosition().getX();
125       lastY = (int) e.getPosition().getY();
126       timer.restart();
127     }
128   }
129 
130   /** The mouse is getting dragged - create an SVET_MOUSE event. */
131   @Override
mouseDragged(PInputEvent e)132   public void mouseDragged(PInputEvent e) {
133     processEvent(new SVEvent(SVEventType.SVET_MOUSE, svWindow, (int) e
134         .getPosition().getX(), (int) e.getPosition().getY(), (int) e
135         .getPosition().getX()
136         - lastX, (int) e.getPosition().getY() - lastY, null));
137 
138     // Paint a selection rectangle.
139     if (selection == null) {
140       startX = (int) e.getPosition().getX();
141       startY = (int) e.getPosition().getY();
142       selection = PPath.createRectangle(startX, startY, 1, 1);
143       selection.setTransparency(rubberBandTransparency);
144       svWindow.canvas.getLayer().addChild(selection);
145     } else {
146       int right = Math.max(startX, (int) e.getPosition().getX());
147       int left = Math.min(startX, (int) e.getPosition().getX());
148       int bottom = Math.max(startY, (int) e.getPosition().getY());
149       int top = Math.min(startY, (int) e.getPosition().getY());
150       svWindow.canvas.getLayer().removeChild(selection);
151       selection = PPath.createRectangle(left, top, right - left, bottom - top);
152       selection.setPaint(Color.YELLOW);
153       selection.setTransparency(rubberBandTransparency);
154       svWindow.canvas.getLayer().addChild(selection);
155     }
156   }
157 
158   /**
159    * The mouse was released.
160    * Depending on the OS, show a popup menu (if the button pressed is associated
161    * with popup menus, like the RMB under windows&linux) or otherwise create an
162    * SVET_SELECTION event.
163    */
164   @Override
mouseReleased(PInputEvent e)165   public void mouseReleased(PInputEvent e) {
166     if (e.isPopupTrigger()) {
167       showPopup(e);
168     } else {
169       processEvent(new SVEvent(SVEventType.SVET_SELECTION, svWindow, (int) e
170           .getPosition().getX(), (int) e.getPosition().getY(), (int) e
171           .getPosition().getX()
172           - lastX, (int) e.getPosition().getY() - lastY, null));
173     }
174     if (selection != null) {
175       svWindow.canvas.getLayer().removeChild(selection);
176     }
177   }
178 
179   /**
180    * The mouse wheel is used to zoom in and out of the viewport and center on
181    * the (x,y) position the mouse is currently on.
182    */
183   @Override
mouseWheelRotated(PInputEvent e)184   public void mouseWheelRotated(PInputEvent e) {
185     PCamera lc = svWindow.canvas.getCamera();
186     double sf = SVWindow.SCALING_FACTOR;
187 
188     if (e.getWheelRotation() < 0) {
189       sf = 1 / sf;
190     }
191     lc.scaleViewAboutPoint(lc.getScale() / sf, e.getPosition().getX(), e
192         .getPosition().getY());
193   }
194 
195   /**
196    * The mouse was moved - create an SVET_MOTION event. NOTE: This obviously
197    * creates a lot of traffic and, depending on the type of application, could
198    * quite possibly be disabled.
199    */
200   @Override
mouseMoved(PInputEvent e)201   public void mouseMoved(PInputEvent e) {
202     processEvent(new SVEvent(SVEventType.SVET_MOTION, svWindow, (int) e
203         .getPosition().getX(), (int) e.getPosition().getY(), 0, 0, null));
204   }
205 
206   /**
207    * The mouse entered the window.
208    * Start the timer, which will then emit SVET_HOVER events every X ms. */
209   @Override
mouseEntered(PInputEvent e)210   public void mouseEntered(PInputEvent e) {
211     timer.restart();
212   }
213 
214   /**
215    * The mouse exited the window
216    * Stop the timer, so no more SVET_HOVER events will emit. */
217   @Override
mouseExited(PInputEvent e)218   public void mouseExited(PInputEvent e) {
219     timer.stop();
220   }
221 
222   /**
223    * The only associated object with this is the timer, so we use it to send a
224    * SVET_HOVER event.
225    */
actionPerformed(ActionEvent e)226   public void actionPerformed(ActionEvent e) {
227     processEvent(new SVEvent(SVEventType.SVET_HOVER, svWindow, lastXMove,
228         lastYMove, 0, 0, null));
229   }
230 
231   /**
232    * A key was pressed - create an SVET_INPUT event.
233    *
234    * NOTE: Might be useful to specify hotkeys.
235    *
236    * Implementation note: The keyListener provided by Piccolo seems to be
237    * broken, so we use the AWT listener directly.
238    * There are never any keyTyped events received either so we are
239    * stuck with physical keys, which is very ugly.
240    */
keyPressed(KeyEvent e)241   public void keyPressed(KeyEvent e) {
242     char keyCh = e.getKeyChar();
243     if (keyCh == '\r' || keyCh == '\n' || keyCh == '\0' || keyCh == '?') {
244       processEvent(new SVEvent(SVEventType.SVET_INPUT, svWindow, lastXMove,
245                                lastYMove, 0, 0, keyStr));
246       // Send newline characters as '!' as '!' can never be a keypressed
247       // and the client eats all newline characters.
248       keyStr = "!";
249     } else {
250       processEvent(new SVEvent(SVEventType.SVET_INPUT, svWindow, lastXMove,
251                                lastYMove, 0, 0, String.valueOf(keyCh)));
252       keyStr += keyCh;
253     }
254   }
255 
256   /**
257    * A window is closed (by the 'x') - create an SVET_DESTROY event. If it was
258    * the last open Window, also send an SVET_EXIT event (but do not exit unless
259    * the client says so).
260    */
windowClosing(WindowEvent e)261   public void windowClosing(WindowEvent e) {
262     processEvent(new SVEvent(SVEventType.SVET_DESTROY, svWindow, lastXMove,
263         lastYMove, 0, 0, null));
264     e.getWindow().dispose();
265     SVWindow.nrWindows--;
266     if (SVWindow.nrWindows == 0) {
267       processEvent(new SVEvent(SVEventType.SVET_EXIT, svWindow, lastXMove,
268           lastYMove, 0, 0, null));
269     }
270   }
271 
272   /** These are all events we do not care about and throw away */
keyReleased(KeyEvent e)273   public void keyReleased(KeyEvent e) {
274   }
275 
keyTyped(KeyEvent e)276   public void keyTyped(KeyEvent e) {
277   }
278 
windowActivated(WindowEvent e)279   public void windowActivated(WindowEvent e) {
280   }
281 
windowClosed(WindowEvent e)282   public void windowClosed(WindowEvent e) {
283   }
284 
windowDeactivated(WindowEvent e)285   public void windowDeactivated(WindowEvent e) {
286   }
287 
windowDeiconified(WindowEvent e)288   public void windowDeiconified(WindowEvent e) {
289   }
290 
windowIconified(WindowEvent e)291   public void windowIconified(WindowEvent e) {
292   }
293 
windowOpened(WindowEvent e)294   public void windowOpened(WindowEvent e) {
295   }
296 }
297