git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@168 72836036-5685-4462-b002-a69064685172
314 lines
9 KiB
Java
314 lines
9 KiB
Java
package jrummikub.view.impl;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Graphics;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Insets;
|
|
import java.awt.Point;
|
|
import java.awt.Shape;
|
|
import java.awt.event.ComponentAdapter;
|
|
import java.awt.event.ComponentEvent;
|
|
import java.awt.geom.AffineTransform;
|
|
import java.awt.geom.Area;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
import javax.swing.ImageIcon;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.SwingUtilities;
|
|
|
|
import jrummikub.model.Position;
|
|
import jrummikub.model.Stone;
|
|
import jrummikub.model.StoneSet;
|
|
import jrummikub.util.Event1;
|
|
import jrummikub.util.IListener1;
|
|
import jrummikub.util.Pair;
|
|
import jrummikub.view.IStoneCollectionPanel;
|
|
import jrummikub.view.ITablePanel;
|
|
|
|
/**
|
|
* The implementation of the table
|
|
*/
|
|
@SuppressWarnings("serial")
|
|
class TablePanel extends AbstractStonePanel implements ITablePanel {
|
|
private final static ImageIcon BACKGROUND = new ImageIcon(
|
|
HandPanel.class.getResource("/jrummikub/resource/felt.png"));
|
|
private final static ImageIcon DARK_BACKGROUND = new ImageIcon(
|
|
HandPanel.class.getResource("/jrummikub/resource/dark_felt.png"));
|
|
|
|
private final static float MIN_VISIBLE_WIDTH = 15;
|
|
private final static float MIN_VISIBLE_HEIGHT = 7.5f;
|
|
private final static float HORIZONTAL_MARGIN = 1.5f;
|
|
private final static float VERTICAL_MARGIN = 1;
|
|
private final static float CONNECTOR_WIDTH = 0.25f;
|
|
private final float COLLECTION_RATIO = 0.12f;
|
|
private final int COLLECTION_GAP = 5;
|
|
|
|
private JLabel leftPlayerLabel, topPlayerLabel, rightPlayerLabel;
|
|
private StoneCollectionPanel stoneCollection;
|
|
|
|
private Iterable<Pair<StoneSet, Position>> stoneSets = Collections.emptySet();
|
|
private Collection<Stone> selectedStones = Collections.emptyList();
|
|
|
|
private Event1<StoneSet> leftConnectorClickEvent = new Event1<StoneSet>();
|
|
private Event1<StoneSet> rightConnectorClickEvent = new Event1<StoneSet>();
|
|
|
|
@Override
|
|
public void setLeftPlayerName(String playerName) {
|
|
leftPlayerLabel.setText(playerName);
|
|
}
|
|
|
|
@Override
|
|
public void setTopPlayerName(String playerName) {
|
|
topPlayerLabel.setText(playerName);
|
|
}
|
|
|
|
@Override
|
|
public void setRightPlayerName(String playerName) {
|
|
rightPlayerLabel.setText(playerName);
|
|
}
|
|
|
|
@Override
|
|
public Event1<StoneSet> getLeftConnectorClickEvent() {
|
|
return leftConnectorClickEvent;
|
|
}
|
|
|
|
@Override
|
|
public Event1<StoneSet> getRightConnectorClickEvent() {
|
|
return rightConnectorClickEvent;
|
|
}
|
|
|
|
@Override
|
|
public void setStoneSets(Iterable<Pair<StoneSet, Position>> stoneSets) {
|
|
List<Pair<Stone, Position>> stones = new ArrayList<Pair<Stone, Position>>();
|
|
|
|
for (Pair<StoneSet, Position> entry : stoneSets) {
|
|
float x = entry.getSecond().getX(), y = entry.getSecond().getY();
|
|
|
|
for (Stone stone : entry.getFirst()) {
|
|
stones.add(new Pair<Stone, Position>(stone, new Position(x, y)));
|
|
x++;
|
|
}
|
|
}
|
|
|
|
setStones(stones);
|
|
this.stoneSets = stoneSets;
|
|
|
|
repaint();
|
|
}
|
|
|
|
@Override
|
|
public IStoneCollectionPanel getStoneCollectionPanel() {
|
|
return stoneCollection;
|
|
}
|
|
|
|
/**
|
|
* Sets the currently selected stones
|
|
*
|
|
* @param stones
|
|
* the selected stones
|
|
*/
|
|
void setSelectedStones(Collection<Stone> stones) {
|
|
selectedStones = stones;
|
|
stoneCollection.setSelectedStones(stones);
|
|
repaint();
|
|
}
|
|
|
|
private void createLabels() {
|
|
leftPlayerLabel = new JLabel();
|
|
leftPlayerLabel.setForeground(Color.WHITE);
|
|
leftPlayerLabel.setHorizontalAlignment(JLabel.LEFT);
|
|
leftPlayerLabel.setHorizontalTextPosition(JLabel.LEFT);
|
|
add(leftPlayerLabel);
|
|
|
|
topPlayerLabel = new JLabel();
|
|
topPlayerLabel.setHorizontalAlignment(JLabel.CENTER);
|
|
topPlayerLabel.setHorizontalTextPosition(JLabel.CENTER);
|
|
topPlayerLabel.setVerticalAlignment(JLabel.TOP);
|
|
topPlayerLabel.setVerticalTextPosition(JLabel.TOP);
|
|
topPlayerLabel.setForeground(Color.WHITE);
|
|
add(topPlayerLabel);
|
|
|
|
rightPlayerLabel = new JLabel();
|
|
rightPlayerLabel.setForeground(Color.WHITE);
|
|
rightPlayerLabel.setHorizontalAlignment(JLabel.RIGHT);
|
|
rightPlayerLabel.setHorizontalTextPosition(JLabel.RIGHT);
|
|
add(rightPlayerLabel);
|
|
}
|
|
|
|
/**
|
|
* Creates a new Table instance
|
|
*/
|
|
TablePanel() {
|
|
setLayout(null);
|
|
|
|
createLabels();
|
|
|
|
stoneCollection = new StoneCollectionPanel();
|
|
stoneCollection.getOtherClickEvent().add(new IListener1<Point>() {
|
|
|
|
@Override
|
|
public void handle(Point p) {
|
|
Point p2 = SwingUtilities.convertPoint(stoneCollection, p, TablePanel.this);
|
|
clickAt(p2, 1, false, false);
|
|
}});
|
|
add(stoneCollection);
|
|
|
|
addComponentListener(new ComponentAdapter() {
|
|
@Override
|
|
public void componentResized(ComponentEvent e) {
|
|
rescale();
|
|
}
|
|
});
|
|
}
|
|
|
|
private Rectangle2D calculateTableExtent() {
|
|
float minx = -MIN_VISIBLE_WIDTH / 2, maxx = MIN_VISIBLE_WIDTH / 2;
|
|
float miny = -MIN_VISIBLE_HEIGHT / 2, maxy = MIN_VISIBLE_HEIGHT / 2;
|
|
|
|
for (Pair<StoneSet, Position> entry : stoneSets) {
|
|
Position p = entry.getSecond();
|
|
StoneSet stoneSet = entry.getFirst();
|
|
|
|
if (p.getX() < minx)
|
|
minx = p.getX();
|
|
|
|
if (p.getY() < miny)
|
|
miny = p.getY();
|
|
|
|
if (p.getX() + stoneSet.size() > maxx)
|
|
maxx = p.getX() + stoneSet.size();
|
|
|
|
if (p.getY() + 1 > maxy)
|
|
maxy = p.getY() + 1;
|
|
}
|
|
|
|
return new Rectangle2D.Float(minx - HORIZONTAL_MARGIN, miny
|
|
- VERTICAL_MARGIN, maxx - minx + 2 * HORIZONTAL_MARGIN, maxy - miny + 2
|
|
* VERTICAL_MARGIN);
|
|
}
|
|
|
|
private void rescale() {
|
|
Insets insets = getInsets();
|
|
int x = insets.left, y = insets.top, width = getWidth() - insets.left
|
|
- insets.right, height = getHeight() - insets.top - insets.bottom;
|
|
|
|
leftPlayerLabel.setBounds(x, y, width, height);
|
|
topPlayerLabel.setBounds(x, y, width, height);
|
|
rightPlayerLabel.setBounds(x, y, width, height);
|
|
|
|
Rectangle2D extent = calculateTableExtent();
|
|
|
|
float widthScale = width / (float) extent.getWidth()
|
|
* StonePainter.WIDTH_SCALE;
|
|
float heightScale = height * (1 - COLLECTION_RATIO)
|
|
/ (float) extent.getHeight() * StonePainter.HEIGHT_SCALE;
|
|
|
|
getStonePainter().setScale(Math.min(widthScale, heightScale));
|
|
|
|
int collectionHeight = (int) (height * COLLECTION_RATIO);
|
|
stoneCollection
|
|
.setBounds(x, y + height - collectionHeight - COLLECTION_GAP, width,
|
|
collectionHeight);
|
|
|
|
repaint();
|
|
}
|
|
|
|
protected boolean handleOtherClickEvent(Position pos) {
|
|
for (Pair<StoneSet, Position> entry : stoneSets) {
|
|
Position p = entry.getSecond();
|
|
StoneSet stoneSet = entry.getFirst();
|
|
float x = p.getX(), y = p.getY();
|
|
|
|
// left connector
|
|
Rectangle2D rect = new Rectangle2D.Float(x - CONNECTOR_WIDTH, y,
|
|
CONNECTOR_WIDTH, 1);
|
|
if (rect.contains(pos.getX(), pos.getY())) {
|
|
leftConnectorClickEvent.emit(stoneSet);
|
|
return true;
|
|
}
|
|
|
|
// right connector
|
|
rect = new Rectangle2D.Float(x + stoneSet.size(), y, CONNECTOR_WIDTH, 1);
|
|
if (rect.contains(pos.getX(), pos.getY())) {
|
|
rightConnectorClickEvent.emit(stoneSet);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected Pair<Integer, Integer> getTranslation() {
|
|
Insets insets = getInsets();
|
|
int width = getWidth() - insets.left - insets.right, height = getHeight()
|
|
- insets.top - insets.bottom;
|
|
int stoneWidth = getStonePainter().getStoneWidth(), stoneHeight = getStonePainter()
|
|
.getStoneHeight();
|
|
Rectangle2D extent = calculateTableExtent();
|
|
|
|
return new Pair<Integer, Integer>((int) (width / 2 - extent.getCenterX()
|
|
* stoneWidth),
|
|
(int) ((height * (1 - COLLECTION_RATIO)) / 2 - extent.getCenterY()
|
|
* stoneHeight));
|
|
}
|
|
|
|
private void paintStoneSet(Graphics2D g, StoneSet stoneSet, Position pos,
|
|
Area connectorArea) {
|
|
float x = pos.getX();
|
|
int width = getStonePainter().getStoneWidth(), height = getStonePainter()
|
|
.getStoneHeight();
|
|
|
|
// Left connector
|
|
connectorArea.add(new Area(new Rectangle2D.Float((int) (x * width - width
|
|
* CONNECTOR_WIDTH), (int) (pos.getY() * height),
|
|
(int) (width * CONNECTOR_WIDTH), height)));
|
|
|
|
for (Stone stone : stoneSet) {
|
|
getStonePainter().paintStone(g, stone, new Position(x, pos.getY()),
|
|
selectedStones.contains(stone), stone == getHoveredStone());
|
|
x++;
|
|
}
|
|
|
|
// Right connector
|
|
connectorArea.add(new Area(new Rectangle2D.Float((int) (x * width),
|
|
(int) (pos.getY() * height), (int) (width * CONNECTOR_WIDTH), height)));
|
|
}
|
|
|
|
@Override
|
|
protected void paintComponent(Graphics g1) {
|
|
Graphics2D g = (Graphics2D) g1;
|
|
|
|
for (int x = 0; x < getWidth(); x += BACKGROUND.getIconWidth()) {
|
|
for (int y = 0; y < getHeight(); y += BACKGROUND.getIconHeight()) {
|
|
BACKGROUND.paintIcon(this, g, x, y);
|
|
}
|
|
}
|
|
|
|
AffineTransform oldTransform = g.getTransform();
|
|
Shape oldClip = g.getClip();
|
|
|
|
Pair<Integer, Integer> translation = getTranslation();
|
|
g.translate(translation.getFirst(), translation.getSecond());
|
|
|
|
Area connectorArea = new Area();
|
|
|
|
for (Pair<StoneSet, Position> entry : stoneSets) {
|
|
paintStoneSet(g, entry.getFirst(), entry.getSecond(), connectorArea);
|
|
}
|
|
|
|
g.setClip(connectorArea);
|
|
g.setTransform(oldTransform);
|
|
|
|
for (int x = 0; x < getWidth(); x += DARK_BACKGROUND.getIconWidth()) {
|
|
for (int y = 0; y < getHeight(); y += DARK_BACKGROUND.getIconHeight()) {
|
|
DARK_BACKGROUND.paintIcon(this, g, x, y);
|
|
}
|
|
}
|
|
|
|
g.setClip(oldClip);
|
|
}
|
|
}
|