/**
* Adds AWT mouse listeners to <code>component3D</code> that calls back <code>controller</code> methods.
*/
private void addMouseListeners(final HomeController3D controller, final Component component3D) {
MouseInputAdapter mouseListener = new MouseInputAdapter() {
private int xLastMouseMove;
private int yLastMouseMove;
private Component grabComponent;
private Component previousMouseEventTarget;
@Override
public void mousePressed(MouseEvent ev) {
if (!retargetMouseEventToNavigationPanelChildren(ev)) {
if (ev.isPopupTrigger()) {
mouseReleased(ev);
} else if (isEnabled()) {
requestFocusInWindow();
this.xLastMouseMove = ev.getX();
this.yLastMouseMove = ev.getY();
}
}
}
@Override
public void mouseReleased(MouseEvent ev) {
if (!retargetMouseEventToNavigationPanelChildren(ev)) {
if (ev.isPopupTrigger()) {
JPopupMenu componentPopupMenu = getComponentPopupMenu();
if (componentPopupMenu != null) {
componentPopupMenu.show(HomeComponent3D.this, ev.getX(), ev.getY());
}
}
}
}
@Override
public void mouseClicked(MouseEvent ev) {
retargetMouseEventToNavigationPanelChildren(ev);
}
@Override
public void mouseMoved(MouseEvent ev) {
retargetMouseEventToNavigationPanelChildren(ev);
}
@Override
public void mouseDragged(MouseEvent ev) {
if (!retargetMouseEventToNavigationPanelChildren(ev)) {
if (isEnabled()) {
if (ev.isAltDown()) {
// Mouse move along Y axis while alt is down changes camera location
float delta = 1.25f * (this.yLastMouseMove - ev.getY());
// Multiply delta by 10 if shift is down
if (ev.isShiftDown()) {
delta *= 5;
}
controller.moveCamera(delta);
} else {
final float ANGLE_FACTOR = 0.005f;
// Mouse move along X axis changes camera yaw
float yawDelta = ANGLE_FACTOR * (ev.getX() - this.xLastMouseMove);
// Multiply yaw delta by 10 if shift is down
if (ev.isShiftDown()) {
yawDelta *= 5;
}
controller.rotateCameraYaw(yawDelta);
// Mouse move along Y axis changes camera pitch
float pitchDelta = ANGLE_FACTOR * (ev.getY() - this.yLastMouseMove);
controller.rotateCameraPitch(pitchDelta);
}
this.xLastMouseMove = ev.getX();
this.yLastMouseMove = ev.getY();
}
}
}
/**
* Retargets to the first component of navigation panel able to manage the given event
* and returns <code>true</code> if a component consumed the event
* or needs to be repainted (meaning its state changed).
* This implementation doesn't cover all the possible cases (mouseEntered and mouseExited
* events are managed only during mouseDragged event).
*/
private boolean retargetMouseEventToNavigationPanelChildren(MouseEvent ev) {
if (navigationPanel != null
&& navigationPanel.isVisible()) {
if (this.grabComponent != null
&& (ev.getID() == MouseEvent.MOUSE_RELEASED
|| ev.getID() == MouseEvent.MOUSE_DRAGGED)) {
Point point = SwingUtilities.convertPoint(ev.getComponent(), ev.getPoint(), this.grabComponent);
dispatchRetargetedEvent(deriveEvent(ev, this.grabComponent, ev.getID(), point.x, point.y));
if (ev.getID() == MouseEvent.MOUSE_RELEASED) {
this.grabComponent = null;
} else {
if (this.previousMouseEventTarget == null
&& this.grabComponent.contains(point)) {
dispatchRetargetedEvent(deriveEvent(ev, this.grabComponent, MouseEvent.MOUSE_ENTERED, point.x, point.y));
this.previousMouseEventTarget = this.grabComponent;
} else if (this.previousMouseEventTarget != null
&& !this.grabComponent.contains(point)) {
dispatchRetargetedEvent(deriveEvent(ev, this.grabComponent, MouseEvent.MOUSE_EXITED, point.x, point.y));
this.previousMouseEventTarget = null;
}
}
return true;
} else {
Component mouseEventTarget = retargetMouseEvent(navigationPanel, ev);
if (mouseEventTarget != null) {
this.previousMouseEventTarget = mouseEventTarget;
return true;
}
}
}
return false;
}
private Component retargetMouseEvent(Component component, MouseEvent ev) {
if (component.getBounds().contains(ev.getPoint())) {
if (component instanceof Container) {
Container container = (Container)component;
for (int i = container.getComponentCount() - 1; i >= 0; i--) {
Component c = container.getComponent(i);
MouseEvent retargetedEvent = deriveEvent(ev, component, ev.getID(),
ev.getX() - component.getX(), ev.getY() - component.getY());
Component mouseEventTarget = retargetMouseEvent(c, retargetedEvent);
if (mouseEventTarget != null) {
return mouseEventTarget;
}
}
}
int newX = ev.getX() - component.getX();
int newY = ev.getY() - component.getY();
if (dispatchRetargetedEvent(deriveEvent(ev, component, ev.getID(), newX, newY))) {
if (ev.getID() == MouseEvent.MOUSE_PRESSED) {
this.grabComponent = component;
}
return component;
}
}
return null;
}
/**
* Dispatches the given event to its component and returns <code>true</code> if component needs to be redrawn.
*/
private boolean dispatchRetargetedEvent(MouseEvent ev) {
ev.getComponent().dispatchEvent(ev);
if (!RepaintManager.currentManager(ev.getComponent()).getDirtyRegion((JComponent)ev.getComponent()).isEmpty()) {
updateNavigationPanelImage();
component3D.repaint();
return true;
}
return false;
}
/**
* Returns a new <code>MouseEvent</code> derived from the one given in parameter.
*/
private MouseEvent deriveEvent(MouseEvent ev, Component component, int id, int x, int y) {
return new MouseEvent(component, id, ev.getWhen(),
ev.getModifiersEx() | ev.getModifiers(), x, y,
ev.getClickCount(), ev.isPopupTrigger(), ev.getButton());
}
};
MouseWheelListener mouseWheelListener = new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent ev) {
if (isEnabled()) {
// Mouse wheel changes camera location
float delta = -2.5f * ev.getWheelRotation();
// Multiply delta by 10 if shift is down
if (ev.isShiftDown()) {
delta *= 5;
}
controller.moveCamera(delta);
}
}
};
component3D.addMouseListener(mouseListener);
component3D.addMouseMotionListener(mouseListener);
component3D.addMouseWheelListener(mouseWheelListener);
// Add a mouse listener to this component to request focus in case user clicks in component border
this.addMouseListener(new MouseInputAdapter() {
@Override
public void mousePressed(MouseEvent e) {
requestFocusInWindow();
}
});