/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.client.gui;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.freecolandroid.repackaged.java.awt.event.MouseEvent;
import org.freecolandroid.repackaged.java.awt.event.MouseMotionListener;
import org.freecolandroid.repackaged.javax.swing.SwingUtilities;
import net.sf.freecol.FreeCol;
import net.sf.freecol.client.ClientOptions;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.common.model.Map;
import net.sf.freecol.common.model.Map.Direction;
import net.sf.freecol.common.model.PathNode;
import net.sf.freecol.common.model.Tile;
/**
* Listens to the mouse being moved at the level of the Canvas.
*/
public final class CanvasMouseMotionListener implements MouseMotionListener {
private static final Logger logger = Logger.getLogger(CanvasMouseMotionListener.class.getName());
// Temporary variable for checking if we need to recalculate the path when
// dragging units.
private Tile lastTile;
private final MapViewer mapViewer;
private final Map map;
private ScrollThread scrollThread;
private FreeColClient freeColClient;
// private static final int SCROLLSPACE = 3;
private static final int DRAG_SCROLLSPACE = 100;
private static final int AUTO_SCROLLSPACE = 1;
/**
* The constructor to use.
*
* @param canvas The component this object gets created for.
* @param mapViewer The GUI that holds information such as screen resolution.
* @param m The Map that is currently being drawn on the Canvas (by the
* GUI).
*/
public CanvasMouseMotionListener(FreeColClient freeColClient, MapViewer mapViewer, Map m) {
this.freeColClient = freeColClient;
this.mapViewer = mapViewer;
this.map = m;
this.scrollThread = null;
}
/**
* Invoked when the mouse has been moved.
*
* @param e The MouseEvent that holds all the information.
*/
public void mouseMoved(MouseEvent e) {
if (e.getComponent().isEnabled()
&& freeColClient.getClientOptions()
.getBoolean(ClientOptions.AUTO_SCROLL)) {
auto_scroll(e.getX(), e.getY());
} else if (scrollThread != null) {
scrollThread.stopScrolling();
scrollThread = null;
}
if (mapViewer.isGotoStarted()) {
if (mapViewer.getActiveUnit() == null) {
mapViewer.stopGoto();
}
Tile tile = mapViewer.convertToMapTile(e.getX(), e.getY());
if (tile != null) {
if (lastTile != tile) {
lastTile = tile;
if (mapViewer.getActiveUnit() != null
&& mapViewer.getActiveUnit().getTile() != tile) {
PathNode dragPath = mapViewer.getActiveUnit().findPath(tile);
mapViewer.setGotoPath(dragPath);
} else {
mapViewer.setGotoPath(null);
}
}
}
}
}
/**
* Invoked when the mouse has been dragged.
*
* @param e The MouseEvent that holds all the information.
*/
public void mouseDragged(MouseEvent e) {
if (e.getComponent().isEnabled()
&& freeColClient.getClientOptions()
.getBoolean(ClientOptions.MAP_SCROLL_ON_DRAG)) {
drag_scroll(e.getX(), e.getY());
} else if (scrollThread != null) {
scrollThread.stopScrolling();
scrollThread = null;
}
Tile tile = mapViewer.convertToMapTile(e.getX(), e.getY());
if (tile != null &&
(e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) {
// only perform the goto for the left mouse button
if (mapViewer.isGotoStarted()) {
if (mapViewer.getActiveUnit() == null) {
mapViewer.stopGoto();
} else {
if (lastTile != tile) {
lastTile = tile;
if (mapViewer.getActiveUnit().getTile() != tile) {
PathNode dragPath = mapViewer.getActiveUnit().findPath(tile);
mapViewer.setGotoPath(dragPath);
} else {
mapViewer.setGotoPath(null);
}
}
}
} else {
mapViewer.startGoto();
}
}
}
private void auto_scroll(int x, int y){
scroll(x, y, AUTO_SCROLLSPACE);
}
private void drag_scroll(int x, int y){
scroll(x, y, DRAG_SCROLLSPACE);
}
private void scroll(int x, int y, int scrollspace) {
/*
* if (y < canvas.getMenuBarHeight()) { if (scrollThread != null) {
* scrollThread.stopScrolling(); scrollThread = null; } return; } else
* if (y < canvas.getMenuBarHeight() + SCROLLSPACE) { y -=
* canvas.getMenuBarHeight(); }
*/
Direction direction;
if ((x < scrollspace) && (y < scrollspace)) {
// Upper-Left
direction = Direction.NW;
} else if ((x >= mapViewer.getWidth() - scrollspace) && (y < scrollspace)) {
// Upper-Right
direction = Direction.NE;
} else if ((x >= mapViewer.getWidth() - scrollspace) && (y >= mapViewer.getHeight() - scrollspace)) {
// Bottom-Right
direction = Direction.SE;
} else if ((x < scrollspace) && (y >= mapViewer.getHeight() - scrollspace)) {
// Bottom-Left
direction = Direction.SW;
} else if (y < scrollspace) {
// Top
direction = Direction.N;
} else if (x >= mapViewer.getWidth() - scrollspace) {
// Right
direction = Direction.E;
} else if (y >= mapViewer.getHeight() - scrollspace) {
// Bottom
direction = Direction.S;
} else if (x < scrollspace) {
// Left
direction = Direction.W;
} else {
// Center
if (scrollThread != null) {
scrollThread.stopScrolling();
scrollThread = null;
}
return;
}
if (scrollThread != null) {
// continue scrolling in a (perhaps new) direction
scrollThread.setDirection(direction);
} else {
// start scrolling in a direction
scrollThread = new ScrollThread(map, mapViewer);
scrollThread.setDirection(direction);
scrollThread.start();
}
}
/**
* Scrolls the view of the Map by moving its focus.
*/
private class ScrollThread extends Thread {
private final Map map;
private final MapViewer mapViewer;
private Direction direction;
private boolean cont;
/**
* The constructor to use.
*
* @param m The Map that needs to be scrolled.
* @param mapViewer The GUI that holds information such as screen resolution.
*/
public ScrollThread(Map m, MapViewer mapViewer) {
super(FreeCol.CLIENT_THREAD+"Mouse scroller");
this.map = m;
this.mapViewer = mapViewer;
this.cont = true;
}
/**
* Sets the direction in which this ScrollThread will scroll.
*
* @param d The direction in which this ScrollThread will scroll.
*/
public void setDirection(Direction d) {
direction = d;
}
/**
* Makes this ScrollThread stop doing what it is supposed to do.
*/
public void stopScrolling() {
cont = false;
}
/**
* Performs the actual scrolling.
*/
@Override
public void run() {
do {
try {
sleep(100);
} catch (InterruptedException e) {
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
int x, y;
Tile t = mapViewer.getFocus();
if (t == null) {
return;
}
t = t.getNeighbourOrNull(direction);
if (t == null) {
return;
}
if (mapViewer.isMapNearTop(t.getY()) && mapViewer.isMapNearTop(mapViewer.getFocus().getY())) {
if (t.getY() > mapViewer.getFocus().getY()) {
y = t.getY();
do {
y += 2;
} while (mapViewer.isMapNearTop(y));
} else {
y = mapViewer.getFocus().getY();
}
} else if (mapViewer.isMapNearBottom(t.getY()) && mapViewer.isMapNearBottom(mapViewer.getFocus().getY())) {
if (t.getY() < mapViewer.getFocus().getY()) {
y = t.getY();
do {
y -= 2;
} while (mapViewer.isMapNearBottom(y));
} else {
y = mapViewer.getFocus().getY();
}
} else {
y = t.getY();
}
if (mapViewer.isMapNearLeft(t.getX(), t.getY())
&& mapViewer.isMapNearLeft(mapViewer.getFocus().getX(), mapViewer.getFocus().getY())) {
if (t.getX() > mapViewer.getFocus().getX()) {
x = t.getX();
do {
x++;
} while (mapViewer.isMapNearLeft(x, y));
} else {
x = mapViewer.getFocus().getX();
}
} else if (mapViewer.isMapNearRight(t.getX(), t.getY())
&& mapViewer.isMapNearRight(mapViewer.getFocus().getX(), mapViewer.getFocus().getY())) {
if (t.getX() < mapViewer.getFocus().getX()) {
x = t.getX();
do {
x--;
} while (mapViewer.isMapNearRight(x, y));
} else {
x = mapViewer.getFocus().getX();
}
} else {
x = t.getX();
}
mapViewer.setFocus(map.getTile(x,y));
} catch (Exception e) {
logger.log(Level.WARNING, "Exception while scrolling!", e);
}
}
});
} catch (InvocationTargetException e) {
logger.log(Level.WARNING, "Scroll thread caught error", e);
cont = false;
} catch (InterruptedException e) {
logger.log(Level.WARNING, "Scroll thread interrupted", e);
cont = false;
}
} while (cont);
}
}
}