/**
* This file is part of JSkat.
*
* JSkat 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 3 of the License, or
* (at your option) any later version.
*
* JSkat 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 JSkat. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jskat.gui.swing.table;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JPanel;
import org.jskat.data.JSkatOptions;
import org.jskat.gui.img.CardFace;
import org.jskat.gui.img.JSkatGraphicRepository;
import org.jskat.util.Card;
import org.jskat.util.CardList;
import org.jskat.util.Player;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Renders all cards of a trick
*/
class TrickPanel extends JPanel implements ComponentListener {
private static final long serialVersionUID = 1L;
private static Logger log = LoggerFactory.getLogger(TrickPanel.class);
private static final double TRICK_SIZE_FACTOR = 1.0d + 2.0d / 3.0d;
private static JSkatOptions options = JSkatOptions.instance();
private final JSkatGraphicRepository bitmaps = JSkatGraphicRepository.INSTANCE;
private final List<Double> cardRotations;
private final List<Player> positions;
private final CardList trick;
private final Random rand = new Random();
private Player userPosition;
private Player rightOpponent;
private Player leftOpponent;
private CardFace cardFace;
private final boolean randomPlacement;
private final double globalScale;
/**
* Constructor
*
* @param randomPlacement
* Random placement of cards
*/
TrickPanel(final boolean randomPlacement) {
this(1.0, randomPlacement);
}
/**
* Constructor
*
* @param globalScale
* Global scale of cards
* @param randomPlacement
* Random placement of cards
*/
TrickPanel(final double globalScale, final boolean randomPlacement) {
this.cardFace = options.getCardSet().getCardFace();
this.randomPlacement = randomPlacement;
this.globalScale = globalScale;
this.trick = new CardList();
this.positions = new ArrayList<>();
this.cardRotations = new ArrayList<>();
setOpaque(false);
addComponentListener(this);
}
/**
* Adds a card to the trick
*
* @param player
* Position of the player
* @param card
* Card
*/
void addCard(final Player player, final Card card) {
this.positions.add(player);
this.trick.add(card);
if (this.randomPlacement) {
this.cardRotations.add(Double.valueOf(0.5 * this.rand.nextDouble() - 0.25));
} else {
this.cardRotations.add(Double.valueOf(0.0));
}
repaint();
}
/**
* Removes the last card
*/
void removeCard() {
this.positions.remove(this.positions.size() - 1);
this.trick.remove(this.trick.size() - 1);
this.cardRotations.remove(this.trick.size() - 1);
repaint();
}
/**
* Removes all cards from the trick
*/
void clearCards() {
this.positions.clear();
this.trick.clear();
this.cardRotations.clear();
repaint();
}
/**
* @see JPanel#paintComponent(Graphics)
*/
@Override
protected synchronized void paintComponent(final Graphics g) {
super.paintComponent(g);
if (isNewCardFace()) {
this.cardFace = options.getCardSet().getCardFace();
}
final int panelWidth = getWidth();
final int panelHeight = getHeight();
final Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
final double cardScale = getCardScale() * this.globalScale;
final Image image = this.bitmaps.getCardImage(Card.CJ);
final double xScaleSize = image.getWidth(this);
final double xAllTrickCardsSize = xScaleSize * TRICK_SIZE_FACTOR;
final double xBorder = (panelWidth * (1 / cardScale) - xAllTrickCardsSize) / 2.0d;
final double yScaleSize = image.getHeight(this);
final double yAllTrickCardsSize = yScaleSize * TRICK_SIZE_FACTOR;
final double yBorder = (panelHeight * (1 / cardScale) - yAllTrickCardsSize) / 2.0d;
for (int i = 0; i < this.trick.size(); i++) {
final Card card = this.trick.get(i);
final Player player = this.positions.get(i);
if (card != null && player != null) {
// Calculate translation
double posX = 0.0d;
double posY = 0.0d;
if (player.equals(this.leftOpponent)) {
posX = xBorder;
posY = yBorder + yScaleSize * (1.0d / 3.0d);
} else if (player.equals(this.rightOpponent)) {
posX = xBorder + xScaleSize * (2.0d / 3.0d);
posY = yBorder;
} else if (player.equals(this.userPosition)) {
posX = xBorder + xScaleSize * (1.0d / 3.0d);
posY = yBorder + yScaleSize * (2.0d / 3.0d);
}
final AffineTransform transform = new AffineTransform();
transform.translate(posX * cardScale, posY * cardScale);
transform.rotate(this.cardRotations.get(i).doubleValue());
transform.scale(cardScale, cardScale);
g2D.drawImage(this.bitmaps.getCardImage(card), transform, this);
}
}
}
private double getCardScale() {
final Image sampleCard = this.bitmaps.getCardImage(Card.CJ);
final double imageWidth = sampleCard.getWidth(this) * TRICK_SIZE_FACTOR;
final double imageHeight = sampleCard.getHeight(this)
* TRICK_SIZE_FACTOR;
final double scaleX = getWidth() / imageWidth;
final double scaleY = getHeight() / imageHeight;
double scaleFactor = 1.0;
if (scaleX < 1.0 || scaleY < 1.0) {
if (scaleX < scaleY) {
scaleFactor = scaleX;
} else {
scaleFactor = scaleY;
}
}
return scaleFactor;
}
boolean isNewCardFace() {
return !this.cardFace.equals(options.getCardSet().getCardFace());
}
void setUserPosition(final Player newUserPosition) {
this.userPosition = newUserPosition;
this.leftOpponent = this.userPosition.getLeftNeighbor();
this.rightOpponent = this.userPosition.getRightNeighbor();
}
@Override
public void componentResized(final ComponentEvent e) {
repaint();
}
@Override
public void componentMoved(final ComponentEvent e) {
// not needed
}
@Override
public void componentShown(final ComponentEvent e) {
repaint();
}
@Override
public void componentHidden(final ComponentEvent e) {
// not needed
}
}