diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
index 5088c45..bac488a 100644
--- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
@@ -220,11 +220,18 @@
/** Minimum font size. */
private double minFontSize = Double.MAX_VALUE;
- /** Default stroke, new BasicStroke()
. Cannot be made static because BasicStroke is not serializable. */
+ /**
+ * Default stroke, new BasicStroke()
. Cannot be made static
+ * because BasicStroke is not serializable.
+ */
private transient Stroke defaultStroke = new BasicStroke();
- /** Default font, 12 point "SansSerif"
. Will be made final in version 2.0. */
- // public static final Font DEFAULT_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 12); jdk 1.6+
+ /**
+ * Default font, 12 point "SansSerif"
. Will be made final in
+ * version 2.0.
+ */
+ // public static final Font DEFAULT_FONT = new Font(Font.SANS_SERIF,
+ // Font.PLAIN, 12); jdk 1.6+
public static final Font DEFAULT_FONT = new Font("SansSerif", Font.PLAIN, 12);
/** Greek threshold in scale. */
@@ -294,7 +301,6 @@
this(component);
}
-
/**
* Ensures the bounds of the underlying component are accurate, and sets the
* bounds of this PNode.
@@ -347,8 +353,9 @@
}
/**
- * Workaround to prevent text-rendering Swing components from drawing an ellipsis incorrectly.
- *
+ * Workaround to prevent text-rendering Swing components from drawing an
+ * ellipsis incorrectly.
+ *
* @param text text
* @param icon icon
* @param iconGap icon gap
@@ -407,8 +414,7 @@
* specified paint context
*/
protected boolean shouldRenderGreek(final PPaintContext paintContext) {
- return paintContext.getScale() < greekThreshold
- || minFontSize * paintContext.getScale() < 0.5;
+ return paintContext.getScale() < greekThreshold || minFontSize * paintContext.getScale() < 0.5;
}
/**
@@ -419,7 +425,7 @@
*
* @param paintContext paint context
*/
- protected void paintGreek(PPaintContext paintContext) {
+ protected void paintGreek(final PPaintContext paintContext) {
final Graphics2D graphics = paintContext.getGraphics();
final Color background = component.getBackground();
final Color foreground = component.getForeground();
@@ -448,7 +454,7 @@
/**
* Paint the Swing component with the specified paint context.
- *
+ *
* @param paintContext paint context
*/
protected void paintComponent(final PPaintContext paintContext) {
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
index ef93621..2d68151 100644
--- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
@@ -59,8 +59,8 @@
}
private void initRepaintManager() {
- final RepaintManager repaintManager = RepaintManager.currentManager(this);
- if (!(repaintManager instanceof PSwingRepaintManager)) {
+ final RepaintManager repaintManager = RepaintManager.currentManager(this);
+ if (!(repaintManager instanceof PSwingRepaintManager)) {
RepaintManager.setCurrentManager(new PSwingRepaintManager());
}
}
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEvent.java
new file mode 100644
index 0000000..f63af63
--- /dev/null
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEvent.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2007 Stephen Chin
+ *
+ * All rights reserved.
+ */
+package edu.umd.cs.piccolox.pswing;
+
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.util.PPickPath;
+
+public interface PSwingEvent {
+ /**
+ * Returns the x,y position of the event in the local coordinate system of
+ * the node the event occurred on.
+ *
+ * @return a Point2D object containing the x and y coordinates local to the
+ * node.
+ */
+ Point2D getLocalPoint();
+
+ /**
+ * Returns the horizontal x position of the event in the local coordinate
+ * system of the node the event occurred on.
+ *
+ * @return x a double indicating horizontal position local to the node.
+ */
+ double getLocalX();
+
+ /**
+ * Returns the vertical y position of the event in the local coordinate
+ * system of the node the event occurred on.
+ *
+ * @return y a double indicating vertical position local to the node.
+ */
+ double getLocalY();
+
+ /**
+ * Determine the event type.
+ *
+ * @return the id
+ */
+ int getID();
+
+ /**
+ * Determine the node the event originated at. If an event percolates up the
+ * tree and is handled by an event listener higher up in the tree than the
+ * original node that generated the event, this returns the original node.
+ * For mouse drag and release events, this is the node that the original
+ * matching press event went to - in other words, the event is 'grabbed' by
+ * the originating node.
+ *
+ * @return the node
+ */
+ PNode getNode();
+
+ /**
+ * Determine the path the event took from the PCanvas down to the visual
+ * component.
+ *
+ * @return the path
+ */
+ PPickPath getPath();
+
+ /**
+ * Determine the node the event originated at. If an event percolates up the
+ * tree and is handled by an event listener higher up in the tree than the
+ * original node that generated the event, this returns the original node.
+ * For mouse drag and release events, this is the node that the original
+ * matching press event went to - in other words, the event is 'grabbed' by
+ * the originating node.
+ *
+ * @return the node
+ */
+ PNode getGrabNode();
+
+ /**
+ * Return the path from the PCanvas down to the currently grabbed object.
+ *
+ * @return the path
+ */
+ PPickPath getGrabPath();
+
+ /**
+ * Get the current node that is under the cursor. This may return a
+ * different result then getGrabNode() when in a MOUSE_RELEASED or
+ * MOUSE_DRAGGED event.
+ *
+ * @return the current node.
+ */
+ PNode getCurrentNode();
+
+ /**
+ * Get the path from the PCanvas down to the visual component currently
+ * under the mouse.This may give a different result then getGrabPath()
+ * during a MOUSE_DRAGGED or MOUSE_RELEASED operation.
+ *
+ * @return the current path.
+ */
+ PPickPath getCurrentPath();
+
+ /**
+ * Calls appropriate method on the listener based on this events ID.
+ *
+ * @param listener the MouseListener or MouseMotionListener to dispatch to.
+ */
+ void dispatchTo(Object listener);
+
+ /**
+ * Set the souce of this event. As the event is fired up the tree the source
+ * of the event will keep changing to reflect the scenegraph object that is
+ * firing the event.
+ *
+ * @param aSource
+ */
+ void setSource(Object aSource);
+
+ /**
+ * Returns this event as a mouse event. This reduces the need to cast
+ * instances of this interface when they are known to all extend MouseEvent.
+ *
+ * @return this object casted to a MouseEvent
+ */
+ MouseEvent asMouseEvent();
+}
\ No newline at end of file
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
index 5706b57..8c56920 100644
--- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
@@ -33,6 +33,7 @@
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
@@ -44,6 +45,7 @@
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.event.PInputEventListener;
+import edu.umd.cs.piccolo.util.PAffineTransform;
import edu.umd.cs.piccolo.util.PAffineTransformException;
/**
@@ -57,34 +59,46 @@
public class PSwingEventHandler implements PInputEventListener {
private PNode listenNode = null; // used to listen to for events
- private boolean active = false; // True when event handlers are set active.
- // The previous component - used to generate mouseEntered and
- // mouseExited events
- private Component prevComponent = null;
+ /** Tracks whether this event handler is active. */
+ private boolean active = false;
- // Previous points used in generating mouseEntered and mouseExited events
+ /**
+ * The previous component - used to generate mouseEntered and mouseExited
+ * events.
+ */
+ private Component previousComponent = null;
+
+ /** Previous point used for mouseEntered and exited events. */
private Point2D prevPoint = null;
- private Point2D prevOff = null;
+
+ /** Previous offset used for mouseEntered and exited events. */
+ private Point2D previousOffset = null;
private boolean recursing = false;// to avoid accidental recursive handling
+ /** Used for tracking the left button's state. */
private final ButtonData leftButtonData = new ButtonData();
- private final ButtonData rightButtonData = new ButtonData();
+
+ /** Used for tracking the middle button's state. */
private final ButtonData middleButtonData = new ButtonData();
+ /** Used for tracking the right button's state. */
+ private final ButtonData rightButtonData = new ButtonData();
+
+ /** The Canvas in which all this pswing activity is taking place. */
private final PSwingCanvas canvas;
/**
* Constructs a new PSwingEventHandler for the given canvas, and a node that
- * will recieve the mouse events.
+ * will receive the mouse events.
*
* @param canvas the canvas associated with this PSwingEventHandler.
* @param node the node the mouse listeners will be attached to.
*/
- public PSwingEventHandler(final PSwingCanvas canvas, final PNode node) {
+ public PSwingEventHandler(final PSwingCanvas canvas, final PNode listenNode) {
this.canvas = canvas;
- listenNode = node;
+ this.listenNode = listenNode;
}
/**
@@ -113,7 +127,7 @@
}
/**
- * Determines if this event handler is active.
+ * Returns if this event handler is active.
*
* @return True if active
*/
@@ -124,38 +138,45 @@
/**
* Finds the component at the specified location (must be showing).
*
- * @param c
+ * @param component
* @param x
* @param y
* @return the component at the specified location.
*/
- private Component findShowingComponentAt(final Component c, final int x, final int y) {
- if (!c.contains(x, y)) {
+ private Component findShowingComponentAt(final Component component, final int x, final int y) {
+ if (!component.contains(x, y)) {
return null;
}
- if (c instanceof Container) {
- final Container contain = (Container) c;
- final int ncomponents = contain.getComponentCount();
- final Component component[] = contain.getComponents();
+ if (component instanceof Container) {
+ final Container contain = (Container) component;
+ final Component child = findShowingChildAt(contain, x, y);
+ if (child != null) {
+ return child;
+ }
+ }
+ return component;
+ }
- for (int i = 0; i < ncomponents; i++) {
- Component comp = component[i];
- if (comp != null) {
- final Point p = comp.getLocation();
- if (comp instanceof Container) {
- comp = findShowingComponentAt(comp, x - (int) p.getX(), y - (int) p.getY());
- }
- else {
- comp = comp.getComponentAt(x - (int) p.getX(), y - (int) p.getY());
- }
- if (comp != null && comp.isShowing()) {
- return comp;
- }
+ private Component findShowingChildAt(final Container container, final int x, final int y) {
+ final Component[] children = container.getComponents();
+
+ for (int i = 0; i < children.length; i++) {
+ Component child = children[i];
+ if (child != null) {
+ final Point p = child.getLocation();
+ if (child instanceof Container) {
+ child = findShowingComponentAt(child, x - p.x, y - p.y);
+ }
+ else {
+ child = child.getComponentAt(x - p.x, y - p.y);
+ }
+ if (child != null && child.isShowing()) {
+ return child;
}
}
}
- return c;
+ return null;
}
/**
@@ -167,55 +188,49 @@
* @param pSwingMouseEvent
* @param aEvent
*/
- void dispatchEvent(final PSwingMouseEvent pSwingMouseEvent, final PInputEvent aEvent) {
- Component comp = null;
- Point2D pt = null;
+ void dispatchEvent(final PSwingEvent pSwingMouseEvent, final PInputEvent aEvent) {
+ final MouseEvent mEvent = pSwingMouseEvent.asMouseEvent();
final PNode pickedNode = pSwingMouseEvent.getPath().getPickedNode();
-
- // The offsets to put the event in the correct context
- int offX = 0;
- int offY = 0;
-
final PNode currentNode = pSwingMouseEvent.getCurrentNode();
- if (currentNode instanceof PSwing) {
+ Component comp = null;
+ Point point = null;
+
+ Point offset = new Point();
+
+ if (currentNode instanceof PSwing && pickedNode.isDescendentOf(canvas.getRoot())) {
final PSwing swing = (PSwing) currentNode;
final PNode grabNode = pickedNode;
- if (grabNode.isDescendentOf(canvas.getRoot())) {
- pt = new Point2D.Double(pSwingMouseEvent.getX(), pSwingMouseEvent.getY());
- cameraToLocal(pSwingMouseEvent.getPath().getTopCamera(), pt, grabNode);
- prevPoint = new Point2D.Double(pt.getX(), pt.getY());
+ point = new Point(mEvent.getX(), mEvent.getY());
+ cameraToLocal(pSwingMouseEvent.getPath().getTopCamera(), point, grabNode);
+ prevPoint = (Point) point.clone();
- // This is only partially fixed to find the deepest
- // component at pt. It needs to do something like
- // package private method:
- // Container.getMouseEventTarget(int,int,boolean)
- comp = findShowingComponentAt(swing.getComponent(), (int) pt.getX(), (int) pt.getY());
+ // This is only partially fixed to find the deepest
+ // component at pt. It needs to do something like
+ // package private method:
+ // Container.getMouseEventTarget(int,int,boolean)
+ comp = findShowingComponentAt(swing.getComponent(), point.x, point.y);
- // We found the right component - but we need to
- // get the offset to put the event in the component's
- // coordinates
- if (comp != null && comp != swing.getComponent()) {
- for (Component c = comp; c != swing.getComponent(); c = c.getParent()) {
- offX += c.getLocation().getX();
- offY += c.getLocation().getY();
- }
+ // We found the right component - but we need to
+ // get the offset to put the event in the component's
+ // coordinates
+ if (comp != null && comp != swing.getComponent()) {
+ offset = extractSwingOffset(comp, swing);
+ }
+
+ // Mouse Pressed gives focus - effects Mouse Drags and
+ // Mouse Releases
+ if (comp != null && isMousePress(pSwingMouseEvent)) {
+ if (SwingUtilities.isLeftMouseButton(mEvent)) {
+ leftButtonData.setState(pickedNode, comp, offset.x, offset.y);
}
-
- // Mouse Pressed gives focus - effects Mouse Drags and
- // Mouse Releases
- if (comp != null && pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED) {
- if (SwingUtilities.isLeftMouseButton(pSwingMouseEvent)) {
- leftButtonData.setState(swing, pickedNode, comp, offX, offY);
- }
- else if (SwingUtilities.isMiddleMouseButton(pSwingMouseEvent)) {
- middleButtonData.setState(swing, pickedNode, comp, offX, offY);
- }
- else if (SwingUtilities.isRightMouseButton(pSwingMouseEvent)) {
- rightButtonData.setState(swing, pickedNode, comp, offX, offY);
- }
+ else if (SwingUtilities.isMiddleMouseButton(mEvent)) {
+ middleButtonData.setState(pickedNode, comp, offset.x, offset.y);
+ }
+ else if (SwingUtilities.isRightMouseButton(mEvent)) {
+ rightButtonData.setState(pickedNode, comp, offset.x, offset.y);
}
}
}
@@ -223,121 +238,143 @@
// This first case we don't want to give events to just
// any Swing component - but to the one that got the
// original mousePressed
- if (pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED
- || pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED) {
-
- // LEFT MOUSE BUTTON
- if (SwingUtilities.isLeftMouseButton(pSwingMouseEvent) && leftButtonData.getFocusedComponent() != null) {
+ if (isDragOrRelease(pSwingMouseEvent)) {
+ if (isLeftMouseButtonOnComponent(mEvent)) {
handleButton(pSwingMouseEvent, aEvent, leftButtonData);
}
- // MIDDLE MOUSE BUTTON
- if (SwingUtilities.isMiddleMouseButton(pSwingMouseEvent) && middleButtonData.getFocusedComponent() != null) {
+ if (isMiddleMouseButtonOnComponent(mEvent)) {
handleButton(pSwingMouseEvent, aEvent, middleButtonData);
}
- // RIGHT MOUSE BUTTON
- if (SwingUtilities.isRightMouseButton(pSwingMouseEvent) && rightButtonData.getFocusedComponent() != null) {
+ if (isRightMouseButtonOnComponent(mEvent)) {
handleButton(pSwingMouseEvent, aEvent, rightButtonData);
}
}
- // This case covers the cases mousePressed, mouseClicked,
- // and mouseMoved events
- else if ((pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED
- || pSwingMouseEvent.getID() == MouseEvent.MOUSE_CLICKED || pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED)
- && comp != null) {
+ else if (isPressOrClickOrMove(pSwingMouseEvent) && comp != null) {
+ final MouseEvent e_temp = new MouseEvent(comp, pSwingMouseEvent.getID(), mEvent.getWhen(), mEvent
+ .getModifiers(), point.x - offset.x, point.y - offset.y, mEvent.getClickCount(), mEvent
+ .isPopupTrigger());
- final MouseEvent e_temp = new MouseEvent(comp, pSwingMouseEvent.getID(), pSwingMouseEvent.getWhen(),
- pSwingMouseEvent.getModifiers(), (int) pt.getX() - offX, (int) pt.getY() - offY, pSwingMouseEvent
- .getClickCount(), pSwingMouseEvent.isPopupTrigger());
+ final PSwingEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ dispatchEvent(comp, e2);
+ }
+ else if (isWheelEvent(pSwingMouseEvent) && comp != null) {
+ final MouseWheelEvent mWEvent = (MouseWheelEvent) mEvent;
+ final MouseWheelEvent e_temp = new MouseWheelEvent(comp, pSwingMouseEvent.getID(), mEvent.getWhen(), mEvent
+ .getModifiers(), point.x - offset.x, point.y - offset.y, mEvent.getClickCount(), mEvent
+ .isPopupTrigger(), mWEvent.getScrollType(), mWEvent.getScrollAmount(), mWEvent.getWheelRotation());
- final PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ final PSwingMouseWheelEvent e2 = new PSwingMouseWheelEvent(e_temp.getID(), e_temp, aEvent);
dispatchEvent(comp, e2);
}
// Now we need to check if an exit or enter event needs to
// be dispatched - this code is independent of the mouseButtons.
// I tested in normal Swing to see the correct behavior.
- if (prevComponent != null) {
+ if (previousComponent != null) {
// This means mouseExited
// This shouldn't happen - since we're only getting node events
if (comp == null || pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED) {
- final MouseEvent e_temp = createExitEvent(pSwingMouseEvent);
+ final MouseEvent e_temp = createExitEvent(mEvent);
- final PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ final PSwingEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
- dispatchEvent(prevComponent, e2);
- prevComponent = null;
+ dispatchEvent(previousComponent, e2);
+ previousComponent = null;
}
// This means mouseExited prevComponent and mouseEntered comp
- else if (prevComponent != comp) {
- MouseEvent e_temp = createExitEvent(pSwingMouseEvent);
- PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
- dispatchEvent(prevComponent, e2);
+ else if (previousComponent != comp) {
+ MouseEvent e_temp = createExitEvent(mEvent);
+ PSwingEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ dispatchEvent(previousComponent, e2);
- e_temp = createEnterEvent(comp, pSwingMouseEvent, offX, offY);
+ e_temp = createEnterEvent(comp, mEvent, offset.x, offset.y);
e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
- comp.dispatchEvent(e2);
+ comp.dispatchEvent(e2.asMouseEvent());
}
}
- else {
- // This means mouseEntered
- if (comp != null) {
- final MouseEvent e_temp = createEnterEvent(comp, pSwingMouseEvent, offX, offY);
- final PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
- dispatchEvent(comp, e2);
- }
+ else if (comp != null) { // This means mouseEntered
+ final MouseEvent e_temp = createEnterEvent(comp, mEvent, offset.x, offset.y);
+ final PSwingEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ dispatchEvent(comp, e2);
}
- // todo add cursors
- // // We have to manager our own Cursors since this is normally
- // // done on the native side
- // if( comp != cursorComponent &&
- // focusNodeLeft == null &&
- // focusNodeMiddle == null &&
- // focusNodeRight == null ) {
- // if( comp != null ) {
- // cursorComponent = comp;
- // canvas.setCursor( comp.getCursor(), false );
- // }
- // else {
- // cursorComponent = null;
- // canvas.resetCursor();
- // }
- // }
-
- // Set the previous variables for next time
- prevComponent = comp;
+ previousComponent = comp;
if (comp != null) {
- prevOff = new Point2D.Double(offX, offY);
+ previousOffset = offset;
}
}
- private MouseEvent createEnterEvent(final Component comp, final PSwingMouseEvent e1, final int offX, final int offY) {
+ private Point extractSwingOffset(final Component comp, final PSwing swing) {
+ int offsetX = 0;
+ int offsetY = 0;
+
+ for (Component c = comp; c != swing.getComponent(); c = c.getParent()) {
+ offsetX += c.getLocation().x;
+ offsetY += c.getLocation().y;
+ }
+
+ return new Point(offsetX, offsetY);
+ }
+
+ private boolean isRightMouseButtonOnComponent(final MouseEvent mEvent) {
+ return SwingUtilities.isRightMouseButton(mEvent) && rightButtonData.getFocusedComponent() != null;
+ }
+
+ private boolean isMiddleMouseButtonOnComponent(final MouseEvent mEvent) {
+ return SwingUtilities.isMiddleMouseButton(mEvent) && middleButtonData.getFocusedComponent() != null;
+ }
+
+ private boolean isLeftMouseButtonOnComponent(final MouseEvent mEvent) {
+ return SwingUtilities.isLeftMouseButton(mEvent) && leftButtonData.getFocusedComponent() != null;
+ }
+
+ private boolean isMousePress(final PSwingEvent pSwingMouseEvent) {
+ return pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED;
+ }
+
+ private boolean isWheelEvent(final PSwingEvent pSwingMouseEvent) {
+ return pSwingMouseEvent.getID() == MouseEvent.MOUSE_WHEEL;
+ }
+
+ private boolean isPressOrClickOrMove(final PSwingEvent pSwingMouseEvent) {
+ return isMousePress(pSwingMouseEvent) || pSwingMouseEvent.getID() == MouseEvent.MOUSE_CLICKED
+ || pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED;
+ }
+
+ private boolean isDragOrRelease(final PSwingEvent pSwingMouseEvent) {
+ return pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED
+ || pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED;
+ }
+
+ private MouseEvent createEnterEvent(final Component comp, final MouseEvent e1, final int offX, final int offY) {
return new MouseEvent(comp, MouseEvent.MOUSE_ENTERED, e1.getWhen(), 0, (int) prevPoint.getX() - offX,
(int) prevPoint.getY() - offY, e1.getClickCount(), e1.isPopupTrigger());
}
- private MouseEvent createExitEvent(final PSwingMouseEvent e1) {
- return new MouseEvent(prevComponent, MouseEvent.MOUSE_EXITED, e1.getWhen(), 0, (int) prevPoint.getX()
- - (int) prevOff.getX(), (int) prevPoint.getY() - (int) prevOff.getY(), e1.getClickCount(), e1
- .isPopupTrigger());
+ private MouseEvent createExitEvent(final MouseEvent e1) {
+ return new MouseEvent(previousComponent, MouseEvent.MOUSE_EXITED, e1.getWhen(), 0, (int) prevPoint.getX()
+ - (int) previousOffset.getX(), (int) prevPoint.getY() - (int) previousOffset.getY(),
+ e1.getClickCount(), e1.isPopupTrigger());
}
- private void handleButton(final PSwingMouseEvent e1, final PInputEvent aEvent, final ButtonData buttonData) {
- Point2D pt;
- if (buttonData.getPNode().isDescendentOf(canvas.getRoot())) {
- pt = new Point2D.Double(e1.getX(), e1.getY());
- cameraToLocal(e1.getPath().getTopCamera(), pt, buttonData.getPNode());
- // todo this probably won't handle viewing through multiple cameras.
- final MouseEvent e_temp = new MouseEvent(buttonData.getFocusedComponent(), e1.getID(), e1.getWhen(), e1
- .getModifiers(), (int) pt.getX() - buttonData.getOffsetX(), (int) pt.getY()
- - buttonData.getOffsetY(), e1.getClickCount(), e1.isPopupTrigger());
+ private void handleButton(final PSwingEvent e1, final PInputEvent aEvent, final ButtonData buttonData) {
+ final MouseEvent m1 = e1.asMouseEvent();
+ if (involvesSceneNode(buttonData)) {
+ // TODO: this probably won't handle viewing through multiple
+ // cameras.
- final PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+ final Point2D pt = new Point2D.Double(m1.getX(), m1.getY());
+ cameraToLocal(e1.getPath().getTopCamera(), pt, buttonData.getPNode());
+ final MouseEvent tempEvent = new MouseEvent(buttonData.getFocusedComponent(), m1.getID(), m1.getWhen(), m1
+ .getModifiers(), (int) pt.getX() - buttonData.getOffsetX(), (int) pt.getY()
+ - buttonData.getOffsetY(), m1.getClickCount(), m1.isPopupTrigger());
+
+ final PSwingEvent e2 = PSwingMouseEvent.createMouseEvent(tempEvent.getID(), tempEvent, aEvent);
dispatchEvent(buttonData.getFocusedComponent(), e2);
}
else {
@@ -346,46 +383,75 @@
// buttonData.getPSwing().repaint(); //Experiment with SliderExample
// (from Martin) suggests this line is unnecessary, and a serious
// problem in performance.
- e1.consume();
+ m1.consume();
if (e1.getID() == MouseEvent.MOUSE_RELEASED) {
buttonData.mouseReleased();
}
}
- private void dispatchEvent(final Component target, final PSwingMouseEvent event) {
+ private boolean involvesSceneNode(final ButtonData buttonData) {
+ return buttonData.getPNode().isDescendentOf(canvas.getRoot());
+ }
+
+ private void dispatchEvent(final Component target, final PSwingEvent event) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
- target.dispatchEvent(event);
+ target.dispatchEvent(event.asMouseEvent());
}
});
}
- private void cameraToLocal(final PCamera topCamera, final Point2D pt, final PNode node) {
- AffineTransform inverse;
- try {
- inverse = topCamera.getViewTransform().createInverse();
- }
- catch (final NoninvertibleTransformException e) {
- throw new PAffineTransformException(e, topCamera.getViewTransform());
- }
-
- /*
- * Only apply the camera's view transform when this node is a descendant
- * of PLayer
- */
- PNode searchNode = node;
- do {
- searchNode = searchNode.getParent();
- if (searchNode instanceof PLayer) {
- inverse.transform(pt, pt);
- break;
- }
- } while (searchNode != null);
-
+ /**
+ * Transforms the given point from camera coordinates to the node's local
+ * system.
+ *
+ * @param camera camera from which coordinates are measured
+ * @param pt point to transform (will be modified)
+ * @param node node from which local coordinates are measured
+ */
+ private void cameraToLocal(final PCamera camera, final Point2D pt, final PNode node) {
if (node != null) {
+ if (descendsFromLayer(node)) {
+ final AffineTransform inverse = invertTransform(camera.getViewTransform());
+ inverse.transform(pt, pt);
+ }
+
node.globalToLocal(pt);
}
- return;
+ }
+
+ /**
+ * Returns true if the provided layer has a PLayer ancestor.
+ *
+ * @param node node being tested
+ *
+ * @return true if node is a descendant of a PLayer
+ */
+ private boolean descendsFromLayer(final PNode node) {
+ PNode searchNode = node;
+ while (searchNode != null) {
+ searchNode = searchNode.getParent();
+ if (searchNode instanceof PLayer) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the inverse transform for the provided transform. Throws
+ * exception if transform is non invertible.
+ *
+ * @param transform transform to invert
+ * @return inverted transform
+ */
+ private AffineTransform invertTransform(final PAffineTransform transform) {
+ try {
+ return transform.createInverse();
+ }
+ catch (final NoninvertibleTransformException e) {
+ throw new PAffineTransformException(e, transform);
+ }
}
/**
@@ -400,12 +466,12 @@
final InputEvent sourceSwingEvent = aEvent.getSourceSwingEvent();
if (sourceSwingEvent instanceof MouseEvent) {
final MouseEvent swingMouseEvent = (MouseEvent) sourceSwingEvent;
- final PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent(swingMouseEvent.getID(),
+ final PSwingEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent(swingMouseEvent.getID(),
swingMouseEvent, aEvent);
if (!recursing) {
recursing = true;
dispatchEvent(pSwingMouseEvent, aEvent);
- if (pSwingMouseEvent.isConsumed()) {
+ if (pSwingMouseEvent.asMouseEvent().isConsumed()) {
aEvent.setHandled(true);
}
recursing = false;
@@ -422,15 +488,12 @@
* Internal Utility class for handling button interactivity.
*/
private static class ButtonData {
- private PSwing focusPSwing = null;
private PNode focusNode = null;
private Component focusComponent = null;
private int focusOffX = 0;
private int focusOffY = 0;
- public void setState(final PSwing swing, final PNode visualNode, final Component comp, final int offX,
- final int offY) {
- focusPSwing = swing;
+ public void setState(final PNode visualNode, final Component comp, final int offX, final int offY) {
focusComponent = comp;
focusNode = visualNode;
focusOffX = offX;
@@ -453,10 +516,6 @@
return focusOffY;
}
- public PSwing getPSwing() {
- return focusPSwing;
- }
-
public void mouseReleased() {
focusComponent = null;
focusNode = null;
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
index b3ab125..0144fbe 100644
--- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
@@ -31,7 +31,7 @@
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
import java.awt.geom.Point2D;
import java.io.Serializable;
@@ -74,7 +74,7 @@
* @author Sam R. Reid
* @author Lance E. Good
*/
-public class PSwingMouseEvent extends MouseEvent implements Serializable {
+public class PSwingMouseEvent extends MouseEvent implements Serializable, PSwingEvent {
/**
*
*/
@@ -104,10 +104,13 @@
* @param e The original Java mouse event when in MOUSE_DRAGGED and
* MOUSE_RELEASED events.
*/
- public static PSwingMouseEvent createMouseEvent(final int id, final MouseEvent e, final PInputEvent pEvent) {
+ public static PSwingEvent createMouseEvent(final int id, final MouseEvent e, final PInputEvent pEvent) {
if (id == MouseEvent.MOUSE_MOVED || id == MouseEvent.MOUSE_DRAGGED) {
return new PSwingMouseMotionEvent(id, e, pEvent);
}
+ else if (id == MouseEvent.MOUSE_WHEEL) {
+ return new PSwingMouseWheelEvent(id, (MouseWheelEvent) e, pEvent);
+ }
else {
return new PSwingMouseEvent(id, e, pEvent);
}
@@ -228,40 +231,25 @@
* @param listener the MouseListener or MouseMotionListener to dispatch to.
*/
public void dispatchTo(final Object listener) {
- if (listener instanceof MouseListener) {
- final MouseListener mouseListener = (MouseListener) listener;
- switch (getID()) {
- case MouseEvent.MOUSE_CLICKED:
- mouseListener.mouseClicked(this);
- break;
- case MouseEvent.MOUSE_ENTERED:
- mouseListener.mouseEntered(this);
- break;
- case MouseEvent.MOUSE_EXITED:
- mouseListener.mouseExited(this);
- break;
- case MouseEvent.MOUSE_PRESSED:
- mouseListener.mousePressed(this);
- break;
- case MouseEvent.MOUSE_RELEASED:
- mouseListener.mouseReleased(this);
- break;
- default:
- throw new RuntimeException("PMouseEvent with bad ID");
- }
- }
- else {
- final MouseMotionListener mouseMotionListener = (MouseMotionListener) listener;
- switch (getID()) {
- case MouseEvent.MOUSE_DRAGGED:
- mouseMotionListener.mouseDragged(this);
- break;
- case MouseEvent.MOUSE_MOVED:
- mouseMotionListener.mouseMoved(this);
- break;
- default:
- throw new RuntimeException("PMouseMotionEvent with bad ID");
- }
+ final MouseListener mouseListener = (MouseListener) listener;
+ switch (getID()) {
+ case MouseEvent.MOUSE_CLICKED:
+ mouseListener.mouseClicked(this);
+ break;
+ case MouseEvent.MOUSE_ENTERED:
+ mouseListener.mouseEntered(this);
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ mouseListener.mouseExited(this);
+ break;
+ case MouseEvent.MOUSE_PRESSED:
+ mouseListener.mousePressed(this);
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ mouseListener.mouseReleased(this);
+ break;
+ default:
+ throw new RuntimeException("PMouseEvent with bad ID");
}
}
@@ -275,4 +263,8 @@
public void setSource(final Object aSource) {
source = aSource;
}
+
+ public MouseEvent asMouseEvent() {
+ return this;
+ }
}
\ No newline at end of file
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseWheelEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseWheelEvent.java
new file mode 100644
index 0000000..d5e4737
--- /dev/null
+++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseWheelEvent.java
@@ -0,0 +1,215 @@
+/**
+ * Copyright (C) 1998-2000 by University of Maryland, College Park, MD
+20742, USA
+ * All rights reserved.
+ */
+package edu.umd.cs.piccolox.pswing;
+
+import java.awt.Component;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.geom.Point2D;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.event.PInputEvent;
+import edu.umd.cs.piccolo.util.PPickPath;
+
+/**
+ * PMouseMotionEvent is an event which indicates that a mouse motion
+ * action occurred in a node.
+ *
PMouseMotionListener
or
+ * PMouseMotionAdapter
object which registered to receive mouse
+ * motion events using the component's addMouseMotionListener
+ * method. (PMouseMotionAdapter
objects implement the
+ * PMouseMotionListener
interface.) Each such listener object gets
+ * a PMouseEvent
containing the mouse motion event.
+ *
+ *
+ * Warning: Serialized objects of this class will not be compatible with
+ * future Piccolo releases. The current serialization support is appropriate for
+ * short term storage or RMI between applications running the same version of
+ * Piccolo. A future release of Piccolo will provide support for long term
+ * persistence.
+ *
+ * @author Benjamin B. Bederson
+ * @author Sam R. Reid
+ * @author Lance E. Good
+ */
+public class PSwingMouseWheelEvent extends MouseWheelEvent implements PSwingEvent {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private final int id;
+ private final PInputEvent event;
+
+ /**
+ * Constructs a new PMouseWheel event from a Java MouseWheelEvent.
+ *
+ * @param id The event type (MOUSE_WHEEL)
+ * @param e The original Java mouse wheel event.
+ */
+ protected PSwingMouseWheelEvent(final int id, final MouseWheelEvent e, final PInputEvent event) {
+ super((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e
+ .getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation());
+ this.id = id;
+ this.event = event;
+ }
+
+ /**
+ * Returns the x,y position of the event in the local coordinate system of
+ * the node the event occurred on.
+ *
+ * @return a Point2D object containing the x and y coordinates local to the
+ * node.
+ */
+ public Point2D getLocalPoint() {
+ return new Point2D.Double(getX(), getY());
+ }
+
+ /**
+ * Returns the horizontal x position of the event in the local coordinate
+ * system of the node the event occurred on.
+ *
+ * @return x a double indicating horizontal position local to the node.
+ */
+ public double getLocalX() {
+ return getLocalPoint().getX();
+ }
+
+ /**
+ * Returns the vertical y position of the event in the local coordinate
+ * system of the node the event occurred on.
+ *
+ * @return y a double indicating vertical position local to the node.
+ */
+ public double getLocalY() {
+ return getLocalPoint().getY();
+ }
+
+ /**
+ * Determine the event type.
+ *
+ * @return the id
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Determine the node the event originated at. If an event percolates up the
+ * tree and is handled by an event listener higher up in the tree than the
+ * original node that generated the event, this returns the original node.
+ * For mouse drag and release events, this is the node that the original
+ * matching press event went to - in other words, the event is 'grabbed' by
+ * the originating node.
+ *
+ * @return the node
+ */
+ public PNode getNode() {
+ return event.getPickedNode();
+ }
+
+ /**
+ * Determine the path the event took from the PCanvas down to the visual
+ * component.
+ *
+ * @return the path
+ */
+ public PPickPath getPath() {
+ return event.getPath();
+ }
+
+ /**
+ * Determine the node the event originated at. If an event percolates up the
+ * tree and is handled by an event listener higher up in the tree than the
+ * original node that generated the event, this returns the original node.
+ * For mouse drag and release events, this is the node that the original
+ * matching press event went to - in other words, the event is 'grabbed' by
+ * the originating node.
+ *
+ * @return the node
+ */
+ public PNode getGrabNode() {
+ return event.getPickedNode();
+ }
+
+ /**
+ * Return the path from the PCanvas down to the currently grabbed object.
+ *
+ * @return the path
+ */
+ public PPickPath getGrabPath() {
+ return getPath();
+ }
+
+ /**
+ * Get the current node that is under the cursor. This may return a
+ * different result then getGrabNode() when in a MOUSE_RELEASED or
+ * MOUSE_DRAGGED event.
+ *
+ * @return the current node.
+ */
+ public PNode getCurrentNode() {
+ return event.getPickedNode();
+ }
+
+ /**
+ * Get the path from the PCanvas down to the visual component currently
+ * under the mouse.This may give a different result then getGrabPath()
+ * durring a MOUSE_DRAGGED or MOUSE_RELEASED operation.
+ *
+ * @return the current path.
+ */
+ public PPickPath getCurrentPath() {
+ return getPath();
+ }
+
+ /**
+ * Calls appropriate method on the listener based on this events ID.
+ *
+ * @param listener the target for dispatch.
+ */
+ public void dispatchTo(final Object listener) {
+ final MouseWheelListener mouseWheelListener = (MouseWheelListener) listener;
+ switch (getID()) {
+ case MouseEvent.MOUSE_WHEEL:
+ mouseWheelListener.mouseWheelMoved(this);
+ break;
+ default:
+ throw new RuntimeException("PMouseWheelEvent with bad ID");
+ }
+ }
+
+ /**
+ * Set the souce of this event. As the event is fired up the tree the source
+ * of the event will keep changing to reflect the scenegraph object that is
+ * firing the event.
+ *
+ * @param aSource
+ */
+ public void setSource(final Object aSource) {
+ source = aSource;
+ }
+
+ /**
+ * Returns this event as a mouse event. This reduces the need to cast
+ * instances of this interface when they are known to all extend MouseEvent.
+ *
+ * @return this object casted to a MouseEvent
+ */
+ public MouseEvent asMouseEvent() {
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
index 4c6bb01..63b3a6a 100644
--- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
+++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
@@ -40,11 +40,11 @@
public void setUp() {
finalizerCallCount = 0;
- }
-
+ }
+
public void testRemovePSwingDoesNothingWithForeignPSwing() {
- PSwingCanvas canvas = new PSwingCanvas();
- PSwing orphanPSwing = new PSwing(new JLabel());
+ final PSwingCanvas canvas = new PSwingCanvas();
+ final PSwing orphanPSwing = new PSwing(new JLabel());
canvas.removePSwing(orphanPSwing);
}
}
diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java
index 3ff96d0..7ec0128 100644
--- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java
+++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java
@@ -38,9 +38,8 @@
import javax.swing.JPanel;
import javax.swing.RepaintManager;
-import edu.umd.cs.piccolo.util.PPaintContext;
-
import junit.framework.TestCase;
+import edu.umd.cs.piccolo.util.PPaintContext;
/**
* JUnit test class to exercise PSwing bugfixes.
@@ -102,7 +101,8 @@
final BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
final Graphics2D graphics = GraphicsEnvironment.getLocalGraphicsEnvironment().createGraphics(img);
- final PPaintContext paintContext = new PPaintContext(graphics);;
+ final PPaintContext paintContext = new PPaintContext(graphics);
+ ;
pSwing.paintComponent(paintContext);
assertEquals(Color.RED.getRGB(), img.getRGB(50, 50));
}