/*
* Copyright (c) 2014 tabletoptool.com team.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* rptools.com team - initial implementation
* tabletoptool.com team - further development
*/
package com.t3.client.tool;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.Set;
import javax.swing.SwingUtilities;
import com.t3.client.AppState;
import com.t3.client.AppUtil;
import com.t3.client.ScreenPoint;
import com.t3.client.TabletopTool;
import com.t3.client.ui.Tool;
import com.t3.client.ui.zone.ZoneRenderer;
import com.t3.guid.GUID;
import com.t3.model.CellPoint;
import com.t3.model.Token;
import com.t3.model.Zone;
import com.t3.swing.SwingUtil;
import com.t3.util.TokenUtil;
/**
*/
public abstract class DefaultTool extends Tool implements MouseListener, MouseMotionListener, MouseWheelListener {
private static final long serialVersionUID = 3258411729238372921L;
private boolean isDraggingMap;
private int dragStartX;
private int dragStartY;
protected int mouseX;
protected int mouseY;
// This is to manage overflowing of map move events (keep things snappy)
private long lastMoveRedraw;
private int mapDX, mapDY;
private static final int REDRAW_DELAY = 25; // millis
protected ZoneRenderer renderer;
@Override
protected void attachTo(ZoneRenderer renderer) {
super.attachTo(renderer);
this.renderer = renderer;
}
@Override
protected void detachFrom(ZoneRenderer renderer) {
this.renderer = null;
super.detachFrom(renderer);
}
public boolean isDraggingMap() {
return isDraggingMap;
}
protected void repaintZone() {
renderer.repaint();
}
protected Zone getZone() {
return renderer.getZone();
}
////
// Mouse
@Override
public void mousePressed(MouseEvent e) {
// Potential map dragging
if (SwingUtilities.isRightMouseButton(e)) {
dragStartX = e.getX();
dragStartY = e.getY();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (isDraggingMap && SwingUtilities.isRightMouseButton(e)) {
renderer.maybeForcePlayersView();
}
// Cleanup
isDraggingMap = false;
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
@Override
public void mouseClicked(MouseEvent e) {
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
@Override
public void mouseEntered(MouseEvent e) {
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
@Override
public void mouseExited(MouseEvent e) {
}
////
// MouseMotion
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
*/
@Override
public void mouseMoved(MouseEvent e) {
if (renderer == null) {
return;
}
mouseX = e.getX();
mouseY = e.getY();
CellPoint cp = getZone().getGrid().convert(new ScreenPoint(mouseX, mouseY).convertToZone(renderer));
if (cp != null) {
TabletopTool.getFrame().getCoordinateStatusBar().update(cp.x, cp.y);
} else {
TabletopTool.getFrame().getCoordinateStatusBar().clear();
}
}
@Override
public void mouseDragged(MouseEvent e) {
int mX = e.getX();
int mY = e.getY();
CellPoint cellUnderMouse = renderer.getCellAt(new ScreenPoint(mX, mY));
if (cellUnderMouse != null) {
TabletopTool.getFrame().getCoordinateStatusBar().update(cellUnderMouse.x, cellUnderMouse.y);
} else {
TabletopTool.getFrame().getCoordinateStatusBar().clear();
}
// MAP MOVEMENT
if (SwingUtilities.isRightMouseButton(e)) {
isDraggingMap = true;
mapDX += mX - dragStartX;
mapDY += mY - dragStartY;
dragStartX = mX;
dragStartY = mY;
long now = System.currentTimeMillis();
if (now - lastMoveRedraw > REDRAW_DELAY) {
// TODO: does it matter to capture the last map move in the series ?
// TODO: This should probably be genericized and put into ZoneRenderer to prevent over zealous repainting
renderer.moveViewBy(mapDX, mapDY);
mapDX = 0;
mapDY = 0;
lastMoveRedraw = now;
}
}
}
////
// Mouse Wheel
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
// Fix for High Resolution Mouse Wheels
if(e.getWheelRotation() == 0) {
return;
}
// QUICK ROTATE
if (SwingUtil.isShiftDown(e)) {
Set<GUID> tokenGUIDSet = renderer.getSelectedTokenSet();
if (tokenGUIDSet.isEmpty()) {
return;
}
for (GUID tokenGUID : tokenGUIDSet) {
Token token = getZone().getToken(tokenGUID);
if (token == null) {
continue;
}
if (!AppUtil.playerOwns(token)) {
continue;
}
Integer facing = token.getFacing();
if (facing == null) {
facing = -90; // natural alignment
}
if (SwingUtil.isControlDown(e)) {
facing += e.getWheelRotation() > 0 ? 5 : -5;
} else {
int[] facingArray = getZone().getGrid().getFacingAngles();
int facingIndex = TokenUtil.getIndexNearestTo(facingArray, facing);
facingIndex += e.getWheelRotation() > 0 ? 1 : -1;
if (facingIndex < 0) {
facingIndex = facingArray.length - 1;
}
if (facingIndex == facingArray.length) {
facingIndex = 0;
}
facing = facingArray[facingIndex];
}
token.setFacing(facing);
renderer.flush(token);
TabletopTool.serverCommand().putToken(getZone().getId(), token);
}
repaintZone();
return;
}
// ZOOM
if (!AppState.isZoomLocked()) {
boolean direction = e.getWheelRotation() > 0;
direction = isKeyDown('z') ? !direction : direction;
if (direction) {
renderer.zoomOut(e.getX(), e.getY());
} else {
renderer.zoomIn(e.getX(), e.getY());
}
renderer.maybeForcePlayersView();
}
}
@Override
protected void resetTool() {
TabletopTool.getFrame().getToolbox().setSelectedTool(PointerTool.class);
}
}