/*******************************************************************************
* Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*
* Contributors:
* Pavel Savara
* - Initial implementation
* Flemming N. Larsen
* - Redesigned to use IRobotControls instead of accessing the Battle's
* RobotPeers directly.
*******************************************************************************/
package net.sf.robocode.ui.battleview;
import net.sf.robocode.battle.BattleProperties;
import net.sf.robocode.battle.IBattleManager;
import net.sf.robocode.security.SafeComponent;
import robocode.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.*;
import static java.lang.Math.min;
/**
* This handler is used for observing keyboard and mouse events from the battle view,
* which must be process to the all robots interactive event handlers.
* The mouse events y coordinates are mirrored to comply to the coordinate system
* used in Robocode.
*
* @author Pavel Savara (original)
* @author Flemming N. Larsen (contributor)
*/
public final class InteractiveHandler implements KeyEventDispatcher, MouseListener, MouseMotionListener, MouseWheelListener {
private final IBattleManager battleManager;
private final BattleView battleView;
public InteractiveHandler(IBattleManager battleManager, BattleView battleView) {
this.battleManager = battleManager;
this.battleView = battleView;
}
public boolean dispatchKeyEvent(java.awt.event.KeyEvent e) {
switch (e.getID()) {
case KeyEvent.KEY_TYPED:
handleInteractiveEvent(new KeyTypedEvent(cloneKeyEvent(e)));
break;
case KeyEvent.KEY_PRESSED:
handleInteractiveEvent(new KeyPressedEvent(cloneKeyEvent(e)));
break;
case KeyEvent.KEY_RELEASED:
handleInteractiveEvent(new KeyReleasedEvent(cloneKeyEvent(e)));
break;
}
// Allow KeyboardFocusManager to take further action with regard to the KeyEvent.
// This way the InteractiveHandler does not steal the event, but is only a keyboard observer.
return false;
}
public void mouseClicked(MouseEvent e) {
handleInteractiveEvent(new MouseClickedEvent(mirroredMouseEvent(e)));
}
public void mouseEntered(MouseEvent e) {
handleInteractiveEvent(new MouseEnteredEvent(mirroredMouseEvent(e)));
}
public void mouseExited(MouseEvent e) {
handleInteractiveEvent(new MouseExitedEvent(mirroredMouseEvent(e)));
}
public void mousePressed(MouseEvent e) {
handleInteractiveEvent(new MousePressedEvent(mirroredMouseEvent(e)));
}
public void mouseReleased(MouseEvent e) {
handleInteractiveEvent(new MouseReleasedEvent(mirroredMouseEvent(e)));
}
public void mouseMoved(MouseEvent e) {
handleInteractiveEvent(new MouseMovedEvent(mirroredMouseEvent(e)));
}
public void mouseDragged(MouseEvent e) {
handleInteractiveEvent(new MouseDraggedEvent(mirroredMouseEvent(e)));
}
public void mouseWheelMoved(MouseWheelEvent e) {
handleInteractiveEvent(new MouseWheelMovedEvent(mirroredMouseWheelEvent(e)));
}
public static KeyEvent cloneKeyEvent(final KeyEvent e) {
return new KeyEvent(SafeComponent.getSafeEventComponent(), e.getID(), e.getWhen(), e.getModifiersEx(),
e.getKeyCode(), e.getKeyChar(), e.getKeyLocation());
}
private void handleInteractiveEvent(robocode.Event event) {
battleManager.sendInteractiveEvent(event);
}
private MouseEvent mirroredMouseEvent(final MouseEvent e) {
double scale;
BattleProperties battleProps = battleManager.getBattleProperties();
int vWidth = battleView.getWidth();
int vHeight = battleView.getHeight();
int fWidth = battleProps.getBattlefieldWidth();
int fHeight = battleProps.getBattlefieldHeight();
if (vWidth < fWidth || vHeight < fHeight) {
scale = min((double) vWidth / fWidth, (double) fHeight / fHeight);
} else {
scale = 1;
}
double dx = (vWidth - scale * fWidth) / 2;
double dy = (vHeight - scale * fHeight) / 2;
int x = (int) ((e.getX() - dx) / scale + 0.5);
int y = (int) (fHeight - (e.getY() - dy) / scale + 0.5);
return new MouseEvent(SafeComponent.getSafeEventComponent(), e.getID(), e.getWhen(), e.getModifiersEx(), x, y,
e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
private MouseWheelEvent mirroredMouseWheelEvent(final MouseWheelEvent e) {
double scale;
BattleProperties battleProps = battleManager.getBattleProperties();
int vWidth = battleView.getWidth();
int vHeight = battleView.getHeight();
int fWidth = battleProps.getBattlefieldWidth();
int fHeight = battleProps.getBattlefieldHeight();
if (vWidth < fWidth || vHeight < fHeight) {
scale = min((double) vWidth / fWidth, (double) fHeight / fHeight);
} else {
scale = 1;
}
double dx = (vWidth - scale * fWidth) / 2;
double dy = (vHeight - scale * fHeight) / 2;
int x = (int) ((e.getX() - dx) / scale + 0.5);
int y = (int) (fHeight - (e.getY() - dy) / scale + 0.5);
return new MouseWheelEvent(SafeComponent.getSafeEventComponent(), e.getID(), e.getWhen(), e.getModifiersEx(), x,
y, e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation());
}
}