
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@209 72836036-5685-4462-b002-a69064685172
223 lines
5 KiB
Java
223 lines
5 KiB
Java
package jrummikub.view.impl;
|
|
|
|
import java.awt.Insets;
|
|
import java.awt.Point;
|
|
import java.awt.event.MouseAdapter;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseMotionAdapter;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.util.Collections;
|
|
|
|
import javax.swing.JPanel;
|
|
|
|
import jrummikub.model.Position;
|
|
import jrummikub.model.Stone;
|
|
import jrummikub.util.Event1;
|
|
import jrummikub.util.Event2;
|
|
import jrummikub.util.Pair;
|
|
import jrummikub.view.IClickable;
|
|
import jrummikub.view.IStonePanel;
|
|
|
|
/**
|
|
* Base class for panels that draw stones
|
|
*/
|
|
@SuppressWarnings("serial")
|
|
abstract class AbstractStonePanel extends JPanel implements IStonePanel,
|
|
IClickable {
|
|
private StonePainter stonePainter;
|
|
|
|
private Event1<Position> clickEvent = new Event1<Position>();
|
|
private Event2<Stone, Boolean> stoneClickEvent = new Event2<Stone, Boolean>();
|
|
private Event2<Stone, Boolean> rangeClickEvent = new Event2<Stone, Boolean>();
|
|
private Event2<Stone, Boolean> setClickEvent = new Event2<Stone, Boolean>();
|
|
|
|
private Iterable<Pair<Stone, Position>> stones = Collections.emptySet();
|
|
private Stone hoveredStone = null;
|
|
|
|
/**
|
|
* @return the stone painter
|
|
*/
|
|
protected StonePainter getStonePainter() {
|
|
return stonePainter;
|
|
}
|
|
|
|
/**
|
|
* Create a new StonePanel with default scale factor
|
|
*/
|
|
public AbstractStonePanel() {
|
|
this(1);
|
|
}
|
|
|
|
/**
|
|
* Create a new StonePanel with a given scale factor
|
|
*
|
|
* @param scale
|
|
* the grid scale
|
|
*/
|
|
public AbstractStonePanel(float scale) {
|
|
super(true); // Set double buffered
|
|
|
|
stonePainter = new StonePainter(scale);
|
|
|
|
addMouseListener(new MouseAdapter() {
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
clickAt(e.getPoint(), e.getClickCount(), e.isShiftDown(),
|
|
e.isControlDown(), e.isAltDown());
|
|
}
|
|
|
|
@Override
|
|
public void mouseExited(MouseEvent e) {
|
|
setHoveredStone(null);
|
|
}
|
|
});
|
|
|
|
addMouseMotionListener(new MouseMotionAdapter() {
|
|
@Override
|
|
public void mouseMoved(MouseEvent e) {
|
|
Insets insets = getInsets();
|
|
Pair<Integer, Integer> trans = getTranslation();
|
|
Position pos = stonePainter.calculatePosition(e.getX() - insets.left
|
|
- trans.getFirst(), e.getY() - insets.top - trans.getSecond());
|
|
|
|
setHoveredStone(getStoneAt(pos));
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* clickAt is called when a click has occurred
|
|
*
|
|
* @param p
|
|
* the point in component coordinates
|
|
* @param clickCount
|
|
* the click count
|
|
* @param shift
|
|
* is shift down?
|
|
* @param control
|
|
* is control down?
|
|
* @param alt
|
|
* is alt down?
|
|
*/
|
|
protected void clickAt(Point p, int clickCount, boolean shift,
|
|
boolean control, boolean alt) {
|
|
Insets insets = getInsets();
|
|
Pair<Integer, Integer> trans = getTranslation();
|
|
Position pos = stonePainter.calculatePosition(
|
|
p.x - insets.left - trans.getFirst(),
|
|
p.y - insets.top - trans.getSecond());
|
|
if (alt) {
|
|
clickEvent.emit(pos);
|
|
return;
|
|
}
|
|
|
|
Stone stone = getStoneAt(pos);
|
|
|
|
if (stone == null) {
|
|
if (!handleOtherClickEvent(pos))
|
|
clickEvent.emit(pos);
|
|
|
|
return;
|
|
}
|
|
|
|
Event2<Stone, Boolean> event = stoneClickEvent;
|
|
|
|
if (shift)
|
|
event = rangeClickEvent;
|
|
else if (clickCount >= 2)
|
|
event = setClickEvent;
|
|
|
|
event.emit(stone, control);
|
|
}
|
|
|
|
private void setHoveredStone(Stone stone) {
|
|
Stone oldStone = hoveredStone;
|
|
hoveredStone = stone;
|
|
|
|
if (oldStone != hoveredStone)
|
|
repaint();
|
|
}
|
|
|
|
/**
|
|
* Returns the stone the mouse pointer is hovering over
|
|
*
|
|
* @return the hovered stone
|
|
*/
|
|
protected Stone getHoveredStone() {
|
|
return hoveredStone;
|
|
}
|
|
|
|
/**
|
|
* *Overwrite this method* to signal if special zone was clicked
|
|
*
|
|
* @param pos
|
|
* the clicked position
|
|
*
|
|
* @return special zone clicked
|
|
*/
|
|
protected boolean handleOtherClickEvent(Position pos) {
|
|
return false;
|
|
}
|
|
|
|
private Stone getStoneAt(Position pos) {
|
|
for (Pair<Stone, Position> entry : stones) {
|
|
Stone stone = entry.getFirst();
|
|
Position p = entry.getSecond();
|
|
Rectangle2D rect = new Rectangle2D.Float(p.getX(), p.getY(), 1, 1);
|
|
|
|
if (rect.contains(pos.getX(), pos.getY()))
|
|
return stone;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Sets the list of stones that can be clicked on
|
|
*
|
|
* @param stones
|
|
* the stones and positions
|
|
*/
|
|
protected void setStones(Iterable<Pair<Stone, Position>> stones) {
|
|
this.stones = stones;
|
|
}
|
|
|
|
/**
|
|
* Returns the translation in pixels the stones in this panel are painted with
|
|
*
|
|
* @return the translation
|
|
*/
|
|
protected Pair<Integer, Integer> getTranslation() {
|
|
return new Pair<Integer, Integer>(0, 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the list of stones and positions currently set
|
|
*
|
|
* @return the stones
|
|
*/
|
|
protected Iterable<Pair<Stone, Position>> getStones() {
|
|
return stones;
|
|
}
|
|
|
|
@Override
|
|
public Event1<Position> getClickEvent() {
|
|
return clickEvent;
|
|
}
|
|
|
|
@Override
|
|
public Event2<Stone, Boolean> getStoneClickEvent() {
|
|
return stoneClickEvent;
|
|
}
|
|
|
|
@Override
|
|
public Event2<Stone, Boolean> getRangeClickEvent() {
|
|
return rangeClickEvent;
|
|
}
|
|
|
|
@Override
|
|
public Event2<Stone, Boolean> getSetClickEvent() {
|
|
return setClickEvent;
|
|
}
|
|
|
|
}
|