diff --git a/extras/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java b/extras/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java index 2b852a8..ee777c9 100644 --- a/extras/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java +++ b/extras/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java @@ -1,449 +1,460 @@ -/** - * Copyright (C) 1998-2000 by University of Maryland, College Park, MD 20742, USA - * All rights reserved. - */ -package edu.umd.cs.piccolox.pswing; - -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.event.PInputEvent; -import edu.umd.cs.piccolo.event.PInputEventListener; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; - -/** - * Event handler to send MousePressed, MouseReleased, MouseMoved, - * MouseClicked, and MouseDragged events on Swing components within - * a PCanvas. - * - * @author Ben Bederson - * @author Lance Good - * @author Sam Reid - */ -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; - - // Previous points used in generating mouseEntered and mouseExited events - private Point2D prevPoint = null; - private Point2D prevOff = null; - - private boolean recursing = false;//to avoid accidental recursive handling - - private ButtonData leftButtonData = new ButtonData(); - private ButtonData rightButtonData = new ButtonData(); - private ButtonData middleButtonData = new ButtonData(); - - private PSwingCanvas canvas; - - /** - * Constructs a new PSwingEventHandler for the given canvas, - * and a node that will recieve the mouse events. - * - * @param canvas the canvas associated with this PSwingEventHandler. - * @param node the node the mouse listeners will be attached to. - */ - public PSwingEventHandler( PSwingCanvas canvas, PNode node ) { - this.canvas = canvas; - listenNode = node; - } - - /** - * Constructs a new PSwingEventHandler for the given canvas. - */ - public PSwingEventHandler( PSwingCanvas canvas ) { - this.canvas = canvas; - } - - /** - * Sets whether this event handler can fire events. - * - * @param active - */ - void setActive( boolean active ) { - if( this.active && !active ) { - if( listenNode != null ) { - this.active = false; - listenNode.removeInputEventListener( this ); - } - } - else if( !this.active && active ) { - if( listenNode != null ) { - this.active = true; - listenNode.addInputEventListener( this ); - } - } - } - - /** - * Determines if this event handler is active. - * - * @return True if active - */ - public boolean isActive() { - return active; - } - - /** - * Finds the component at the specified location (must be showing). - * - * @param c - * @param x - * @param y - * @return the component at the specified location. - */ - private Component findShowingComponentAt( Component c, int x, int y ) { - if( !c.contains( x, y ) ) { - return null; - } - - if( c instanceof Container ) { - Container contain = ( (Container)c ); - int ncomponents = contain.getComponentCount(); - Component component[] = contain.getComponents(); - - for( int i = 0; i < ncomponents; i++ ) { - Component comp = component[i]; - if( comp != null ) { - 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; - } - } - } - } - return c; - } - - /** - * Determines if any Swing components in Piccolo - * should receive the given MouseEvent and - * forwards the event to that component. - * However, mouseEntered and mouseExited are independent of the buttons. - * Also, notice the notes on mouseEntered and mouseExited. - * - * @param pSwingMouseEvent - * @param aEvent - */ - void dispatchEvent( PSwingMouseEvent pSwingMouseEvent, PInputEvent aEvent ) { - Component comp = null; - Point2D pt = null; - PNode pickedNode = pSwingMouseEvent.getPath().getPickedNode(); - - // The offsets to put the event in the correct context - int offX = 0; - int offY = 0; - - PNode currentNode = pSwingMouseEvent.getCurrentNode(); - - if( currentNode instanceof PSwing ) { - - PSwing swing = (PSwing)currentNode; - 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() ); - - // 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() ); - - // 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(); - } - } - - // 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 ); - } - } - } - } - - // 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 ) { - handleButton( pSwingMouseEvent, aEvent, leftButtonData ); - } - - // MIDDLE MOUSE BUTTON - if( SwingUtilities.isMiddleMouseButton( pSwingMouseEvent ) && middleButtonData.getFocusedComponent() != null ) - { - handleButton( pSwingMouseEvent, aEvent, middleButtonData ); - } - - // RIGHT MOUSE BUTTON - if( SwingUtilities.isRightMouseButton( pSwingMouseEvent ) && rightButtonData.getFocusedComponent() != null ) - { - 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 ) ) { - - MouseEvent e_temp = new MouseEvent( comp, - pSwingMouseEvent.getID(), - pSwingMouseEvent.getWhen(), - pSwingMouseEvent.getModifiers(), - (int)pt.getX() - offX, - (int)pt.getY() - offY, - pSwingMouseEvent.getClickCount(), - pSwingMouseEvent.isPopupTrigger() ); - - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( comp, e2 ); - pSwingMouseEvent.consume(); - } - - // 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 ) { - // This means mouseExited - - // This shouldn't happen - since we're only getting node events - if( comp == null || pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { - MouseEvent e_temp = createExitEvent( pSwingMouseEvent ); - - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - - dispatchEvent( prevComponent, e2 ); - prevComponent = null; - - if( pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { - pSwingMouseEvent.consume(); - } - } - - // 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 ); - - e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); - e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - comp.dispatchEvent( e2 ); - } - } - else { - // This means mouseEntered - if( comp != null ) { - MouseEvent e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); - PSwingMouseEvent 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; - - if( comp != null ) { - prevOff = new Point2D.Double( offX, offY ); - } - } - - private MouseEvent createEnterEvent( Component comp, PSwingMouseEvent e1, int offX, 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( 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 void handleButton( PSwingMouseEvent e1, PInputEvent aEvent, 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. - 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() ); - - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( buttonData.getFocusedComponent(), e2 ); - } - else { - dispatchEvent( buttonData.getFocusedComponent(), e1 ); - } - //buttonData.getPSwing().repaint(); //Experiment with SliderExample (from Martin) suggests this line is unnecessary, and a serious problem in performance. - e1.consume(); - if( e1.getID() == MouseEvent.MOUSE_RELEASED ) { - buttonData.mouseReleased(); - } - } - - private void dispatchEvent( final Component target, final PSwingMouseEvent event ) { - SwingUtilities.invokeLater( new Runnable() { - public void run() { - target.dispatchEvent( event ); - } - } ); - } - - private void cameraToLocal( PCamera topCamera, Point2D pt, PNode node ) { - AffineTransform inverse = null; - try { - inverse = topCamera.getViewTransform().createInverse(); - } - catch( NoninvertibleTransformException e ) { - e.printStackTrace(); - } - inverse.transform( pt, pt ); - if( node != null ) { - node.globalToLocal( pt ); - } - return; - } - - /** - * Process a piccolo event and (if active) dispatch the corresponding Swing event. - * - * @param aEvent - * @param type - */ - public void processEvent( PInputEvent aEvent, int type ) { - if(aEvent.isMouseEvent()) { - InputEvent sourceSwingEvent = aEvent.getSourceSwingEvent(); - if (sourceSwingEvent instanceof MouseEvent) { - MouseEvent swingMouseEvent = (MouseEvent) sourceSwingEvent; - PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( swingMouseEvent.getID(), swingMouseEvent, aEvent ); - if( !recursing ) { - recursing = true; - dispatchEvent( pSwingMouseEvent, aEvent ); - recursing = false; - } - } else { - new Exception("PInputEvent.getSourceSwingEvent was not a MouseEvent. Actual event: " + sourceSwingEvent + ", class=" + sourceSwingEvent.getClass().getName() ).printStackTrace(); - } - } - -/* if( !( EventQueue.getCurrentEvent() instanceof MouseEvent ) ) { - new Exception( "EventQueue.getCurrentEvent was not a MouseEvent, consider making PInputEvent.getSourceSwingEvent public. Actual event: " + EventQueue.getCurrentEvent() + ", class=" + EventQueue.getCurrentEvent().getClass().getName() ).printStackTrace(); - } - if( aEvent.isMouseEvent() && EventQueue.getCurrentEvent() instanceof MouseEvent ) { - MouseEvent sourceSwingEvent = (MouseEvent)EventQueue.getCurrentEvent(); - PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( sourceSwingEvent.getID(), sourceSwingEvent, aEvent ); - if( !recursing ) { - recursing = true; - dispatchEvent( pSwingMouseEvent, aEvent ); - recursing = false; - } - } -*/ - } - - /** - * 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( PSwing swing, PNode visualNode, Component comp, int offX, int offY ) { - focusPSwing = swing; - focusComponent = comp; - focusNode = visualNode; - focusOffX = offX; - focusOffY = offY; - } - - public Component getFocusedComponent() { - return focusComponent; - } - - public PNode getPNode() { - return focusNode; - } - - public int getOffsetX() { - return focusOffX; - } - - public int getOffsetY() { - return focusOffY; - } - - public PSwing getPSwing() { - return focusPSwing; - } - - public void mouseReleased() { - focusComponent = null; - focusNode = null; - } - } -} +/** + * Copyright (C) 1998-2000 by University of Maryland, College Park, MD 20742, USA + * All rights reserved. + */ +package edu.umd.cs.piccolox.pswing; + +import edu.umd.cs.piccolo.PCamera; +import edu.umd.cs.piccolo.PLayer; +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.event.PInputEvent; +import edu.umd.cs.piccolo.event.PInputEventListener; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; + +/** + * Event handler to send MousePressed, MouseReleased, MouseMoved, + * MouseClicked, and MouseDragged events on Swing components within + * a PCanvas. + * + * @author Ben Bederson + * @author Lance Good + * @author Sam Reid + */ +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; + + // Previous points used in generating mouseEntered and mouseExited events + private Point2D prevPoint = null; + private Point2D prevOff = null; + + private boolean recursing = false;//to avoid accidental recursive handling + + private ButtonData leftButtonData = new ButtonData(); + private ButtonData rightButtonData = new ButtonData(); + private ButtonData middleButtonData = new ButtonData(); + + private PSwingCanvas canvas; + + /** + * Constructs a new PSwingEventHandler for the given canvas, + * and a node that will recieve the mouse events. + * + * @param canvas the canvas associated with this PSwingEventHandler. + * @param node the node the mouse listeners will be attached to. + */ + public PSwingEventHandler( PSwingCanvas canvas, PNode node ) { + this.canvas = canvas; + listenNode = node; + } + + /** + * Constructs a new PSwingEventHandler for the given canvas. + */ + public PSwingEventHandler( PSwingCanvas canvas ) { + this.canvas = canvas; + } + + /** + * Sets whether this event handler can fire events. + * + * @param active + */ + void setActive( boolean active ) { + if( this.active && !active ) { + if( listenNode != null ) { + this.active = false; + listenNode.removeInputEventListener( this ); + } + } + else if( !this.active && active ) { + if( listenNode != null ) { + this.active = true; + listenNode.addInputEventListener( this ); + } + } + } + + /** + * Determines if this event handler is active. + * + * @return True if active + */ + public boolean isActive() { + return active; + } + + /** + * Finds the component at the specified location (must be showing). + * + * @param c + * @param x + * @param y + * @return the component at the specified location. + */ + private Component findShowingComponentAt( Component c, int x, int y ) { + if( !c.contains( x, y ) ) { + return null; + } + + if( c instanceof Container ) { + Container contain = ( (Container)c ); + int ncomponents = contain.getComponentCount(); + Component component[] = contain.getComponents(); + + for( int i = 0; i < ncomponents; i++ ) { + Component comp = component[i]; + if( comp != null ) { + 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; + } + } + } + } + return c; + } + + /** + * Determines if any Swing components in Piccolo + * should receive the given MouseEvent and + * forwards the event to that component. + * However, mouseEntered and mouseExited are independent of the buttons. + * Also, notice the notes on mouseEntered and mouseExited. + * + * @param pSwingMouseEvent + * @param aEvent + */ + void dispatchEvent( PSwingMouseEvent pSwingMouseEvent, PInputEvent aEvent ) { + Component comp = null; + Point2D pt = null; + PNode pickedNode = pSwingMouseEvent.getPath().getPickedNode(); + + // The offsets to put the event in the correct context + int offX = 0; + int offY = 0; + + PNode currentNode = pSwingMouseEvent.getCurrentNode(); + + if( currentNode instanceof PSwing ) { + + PSwing swing = (PSwing)currentNode; + 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() ); + + // 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() ); + + // 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(); + } + } + + // 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 ); + } + } + } + } + + // 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 ) { + handleButton( pSwingMouseEvent, aEvent, leftButtonData ); + } + + // MIDDLE MOUSE BUTTON + if( SwingUtilities.isMiddleMouseButton( pSwingMouseEvent ) && middleButtonData.getFocusedComponent() != null ) + { + handleButton( pSwingMouseEvent, aEvent, middleButtonData ); + } + + // RIGHT MOUSE BUTTON + if( SwingUtilities.isRightMouseButton( pSwingMouseEvent ) && rightButtonData.getFocusedComponent() != null ) + { + 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 ) ) { + + MouseEvent e_temp = new MouseEvent( comp, + pSwingMouseEvent.getID(), + pSwingMouseEvent.getWhen(), + pSwingMouseEvent.getModifiers(), + (int)pt.getX() - offX, + (int)pt.getY() - offY, + pSwingMouseEvent.getClickCount(), + pSwingMouseEvent.isPopupTrigger() ); + + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); + dispatchEvent( comp, e2 ); + pSwingMouseEvent.consume(); + } + + // 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 ) { + // This means mouseExited + + // This shouldn't happen - since we're only getting node events + if( comp == null || pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { + MouseEvent e_temp = createExitEvent( pSwingMouseEvent ); + + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); + + dispatchEvent( prevComponent, e2 ); + prevComponent = null; + + if( pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { + pSwingMouseEvent.consume(); + } + } + + // 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 ); + + e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); + e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); + comp.dispatchEvent( e2 ); + } + } + else { + // This means mouseEntered + if( comp != null ) { + MouseEvent e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); + PSwingMouseEvent 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; + + if( comp != null ) { + prevOff = new Point2D.Double( offX, offY ); + } + } + + private MouseEvent createEnterEvent( Component comp, PSwingMouseEvent e1, int offX, 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( 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 void handleButton( PSwingMouseEvent e1, PInputEvent aEvent, 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. + 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() ); + + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); + dispatchEvent( buttonData.getFocusedComponent(), e2 ); + } + else { + dispatchEvent( buttonData.getFocusedComponent(), e1 ); + } + //buttonData.getPSwing().repaint(); //Experiment with SliderExample (from Martin) suggests this line is unnecessary, and a serious problem in performance. + e1.consume(); + if( e1.getID() == MouseEvent.MOUSE_RELEASED ) { + buttonData.mouseReleased(); + } + } + + private void dispatchEvent( final Component target, final PSwingMouseEvent event ) { + SwingUtilities.invokeLater( new Runnable() { + public void run() { + target.dispatchEvent( event ); + } + } ); + } + + private void cameraToLocal( PCamera topCamera, Point2D pt, PNode node ) { + AffineTransform inverse = null; + try { + inverse = topCamera.getViewTransform().createInverse(); + } + catch( NoninvertibleTransformException e ) { + e.printStackTrace(); + } + + /* 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); + + if( node != null ) { + node.globalToLocal( pt ); + } + return; + } + + /** + * Process a piccolo event and (if active) dispatch the corresponding Swing event. + * + * @param aEvent + * @param type + */ + public void processEvent( PInputEvent aEvent, int type ) { + if(aEvent.isMouseEvent()) { + InputEvent sourceSwingEvent = aEvent.getSourceSwingEvent(); + if (sourceSwingEvent instanceof MouseEvent) { + MouseEvent swingMouseEvent = (MouseEvent) sourceSwingEvent; + PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( swingMouseEvent.getID(), swingMouseEvent, aEvent ); + if( !recursing ) { + recursing = true; + dispatchEvent( pSwingMouseEvent, aEvent ); + recursing = false; + } + } else { + new Exception("PInputEvent.getSourceSwingEvent was not a MouseEvent. Actual event: " + sourceSwingEvent + ", class=" + sourceSwingEvent.getClass().getName() ).printStackTrace(); + } + } + +/* if( !( EventQueue.getCurrentEvent() instanceof MouseEvent ) ) { + new Exception( "EventQueue.getCurrentEvent was not a MouseEvent, consider making PInputEvent.getSourceSwingEvent public. Actual event: " + EventQueue.getCurrentEvent() + ", class=" + EventQueue.getCurrentEvent().getClass().getName() ).printStackTrace(); + } + if( aEvent.isMouseEvent() && EventQueue.getCurrentEvent() instanceof MouseEvent ) { + MouseEvent sourceSwingEvent = (MouseEvent)EventQueue.getCurrentEvent(); + PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( sourceSwingEvent.getID(), sourceSwingEvent, aEvent ); + if( !recursing ) { + recursing = true; + dispatchEvent( pSwingMouseEvent, aEvent ); + recursing = false; + } + } +*/ + } + + /** + * 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( PSwing swing, PNode visualNode, Component comp, int offX, int offY ) { + focusPSwing = swing; + focusComponent = comp; + focusNode = visualNode; + focusOffX = offX; + focusOffY = offY; + } + + public Component getFocusedComponent() { + return focusComponent; + } + + public PNode getPNode() { + return focusNode; + } + + public int getOffsetX() { + return focusOffX; + } + + public int getOffsetY() { + return focusOffY; + } + + public PSwing getPSwing() { + return focusPSwing; + } + + public void mouseReleased() { + focusComponent = null; + focusNode = null; + } + } +}