Package org.cspoker.client.gui.swt.window

Source Code of org.cspoker.client.gui.swt.window.TableComposite

/**
* This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.cspoker.client.gui.swt.window;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.cspoker.client.common.gamestate.GameState;
import org.cspoker.client.common.playerstate.PlayerState;
import org.cspoker.client.gui.swt.control.CardPaintListener;
import org.cspoker.client.gui.swt.control.Chip;
import org.cspoker.client.gui.swt.control.ClientGUI;
import org.cspoker.common.elements.cards.Card;
import org.cspoker.common.elements.player.PlayerId;
import org.cspoker.common.elements.player.Winner;
import org.cspoker.common.elements.table.SeatId;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;

/**
* The main composite in the game window. Contains the
* {@link PlayerSeatComposite}s and draws the chips on the table etc.
*
* @author stephans
*/
public class TableComposite
    extends ClientComposite {
 
  private final static Logger logger = Logger.getLogger(TableComposite.class);
 
  private Composite communityCardsComposite;
  private Collection<Card> communityCards = new ArrayList<Card>();
 
  private List<PlayerSeatComposite> playerSeatComposites = new ArrayList<PlayerSeatComposite>();
  private List<Canvas> playerBetAreas = new ArrayList<Canvas>();
  private PlayerSeatComposite dealer;
  private Canvas potChipsArea;
 
  /**
   * Creates and initializes a new Table composite. The table composite
   * contains all {@link PlayerSeatComposite}s.
   * <p>
   * It is in particular responsible for drawing chips on the table surface.
   *
   * @param parent The containing {@link GameWindow}
   * @param style Relevant style bits
   */
  public TableComposite(GameWindow parent, int style) {
    super(parent, style);
    initGUI();
  }
 
  /**
   * @see org.eclipse.swt.widgets.Control#getParent()
   */
  @Override
  public GameWindow getParent() {
    return (GameWindow) super.getParent();
  }
 
  /**
   * Initialization of SWT components.
   */
  private void initGUI() {
   
    GridLayout layout = new GridLayout(5, false);
    setLayout(layout);
    GridData tableCompositeLData = new GridData(SWT.FILL, SWT.FILL, true, true);
    tableCompositeLData.heightHint = 750;
    tableCompositeLData.minimumHeight = 300;
    tableCompositeLData.minimumWidth = 600;
    setLayoutData(tableCompositeLData);
    setBackgroundMode(SWT.INHERIT_FORCE);
    insertHolderLabel();
    insertPlayerSeatComposite(new SeatId(0));
    insertHolderLabel();
    insertPlayerSeatComposite(new SeatId(1));
    insertHolderLabel();
    insertHolderLabel();
    insertBetArea();
    insertHolderLabel();
    insertBetArea();
    insertHolderLabel();
    // End second row
    insertPlayerSeatComposite(new SeatId(5));
    insertBetArea();
    insertCommunityCardsComposite();
    insertBetArea();
    insertPlayerSeatComposite(new SeatId(2));
    insertHolderLabel();
    insertBetArea();
    insertPotChipsCanvas();
    insertBetArea();
    insertHolderLabel();
    // End fourth row
    insertHolderLabel();
    insertPlayerSeatComposite(new SeatId(4));
    insertHolderLabel();
    insertPlayerSeatComposite(new SeatId(3));
    insertHolderLabel();
   
    for (int i = 0; i < playerSeatComposites.size(); i++) {
      Canvas chipsForPlayerArea = playerBetAreas.get(i);
      PlayerSeatComposite psc = playerSeatComposites.get(i);
      psc.setChipsArea(chipsForPlayerArea);
     
    }
    // Add a PaintListener for updating chips (redraw() and update())
    addPaintListener(new PaintListener() {
     
      /**
       * PaintListener for the table. Takes redraw area into consideration
       * and redraws only the affected areas
       *
       * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
       */
      public void paintControl(PaintEvent e) {
        if (getGameState() == null) {
          return;
        }
        Rectangle redrawArea = new Rectangle(e.x, e.y, e.width, e.height);
        for (PlayerSeatComposite pc : getPlayerSeatComposites(true)) {
         
          if (getBetPile(pc.getPlayerId()).size() > 0 && redrawArea.intersects(pc.getChipsArea().getBounds())) {
            drawChips(e.gc, pc.getChipsArea().getBounds(), getBetPile(pc.getPlayerId()), false, false);
           
          }
        }
        // Draw dealer chip
        NavigableMap<Chip, Integer> dealerChip = new TreeMap<Chip, Integer>();
        dealerChip.put(Chip.DEALER, 1);
        if (dealer != null && redrawArea.intersects(dealer.getDealerChipLocation())) {
          drawChips(e.gc, dealer.getDealerChipLocation(), Arrays.asList(dealerChip), false, true);
        }
        if (redrawArea.intersects(potChipsArea.getBounds()) && redrawArea.intersects(potChipsArea.getBounds())) {
          int potSize = 0;
          try {
            potSize = getGameState().getPreviousRoundsPotSize();
          } catch (Exception e1) {
            logger.warn(e1);
          }
          drawChips(e.gc, potChipsArea.getBounds(), Arrays.asList(Chip.getDistribution(potSize)), true, false);
        }
      }
    });
  }
 
  /**
   * Configures canvas where the chips in the pots are displayed
   */
  private void insertPotChipsCanvas() {
    potChipsArea = new Canvas(this, SWT.NONE | ClientGUI.COMPOSITE_BORDER_STYLE);
    GridData betAreaLayoutData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
    betAreaLayoutData.widthHint = 5 * (ClientGUI.PREFERRED_CARD_WIDTH + 5);
    betAreaLayoutData.heightHint = 100;
    betAreaLayoutData.minimumWidth = 5 * (ClientGUI.MINIMUM_CARD_WIDTH + 5);
    betAreaLayoutData.minimumHeight = 50;
    potChipsArea.setLayout(new FillLayout());
    potChipsArea.setLayoutData(betAreaLayoutData);
    potChipsArea.setVisible(false);
  }
 
  /**
   * Configures composite containing the community cards
   */
  private void insertCommunityCardsComposite() {
    communityCardsComposite = new Composite(this, SWT.NONE | ClientGUI.COMPOSITE_BORDER_STYLE);
    communityCardsComposite.setLayout(new GridLayout(5, true));
    GridData communityCardsLayoutData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
    communityCardsLayoutData.horizontalSpan = 1;
    communityCardsLayoutData.widthHint = 5 * (ClientGUI.PREFERRED_CARD_WIDTH + 5);
    communityCardsLayoutData.heightHint = ClientGUI.PREFERRED_CARD_HEIGHT;
    communityCardsLayoutData.minimumWidth = 5 * (ClientGUI.MINIMUM_CARD_WIDTH + 5);
    communityCardsLayoutData.minimumHeight = ClientGUI.MINIMUM_CARD_HEIGHT;
    communityCardsComposite.setLayoutData(communityCardsLayoutData);
    communityCardsComposite.setBackgroundMode(SWT.INHERIT_NONE);
    communityCardsComposite.addPaintListener(new CardPaintListener(communityCards, 5, SWT.LEFT, 5));
    return;
  }
 
  /**
   * Insert an Area where chips can be displayed
   */
  private void insertBetArea() {
    Canvas betArea = new Canvas(this, SWT.NONE | ClientGUI.COMPOSITE_BORDER_STYLE);
    GridData betAreaLayoutData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
    betAreaLayoutData.widthHint = 150;
    betAreaLayoutData.heightHint = 100;
    betAreaLayoutData.minimumWidth = 60;
    betAreaLayoutData.minimumHeight = 50;
    betArea.setLayout(new FillLayout());
    betArea.setLayoutData(betAreaLayoutData);
    playerBetAreas.add(betArea);
    betArea.setVisible(false);
  }
 
  /**
   * GUI initialization
   */
  private void insertPlayerSeatComposite(SeatId seatId) {
    playerSeatComposites.add(new PlayerSeatComposite(this, SWT.NONE | ClientGUI.COMPOSITE_BORDER_STYLE, seatId));
  }
 
  /**
   * Insert invisible dummy label in Grid to occupy Grid cell
   */
  private void insertHolderLabel() {
    new Label(this, SWT.NONE | ClientGUI.COMPOSITE_BORDER_STYLE).setVisible(false);
  }
 
  /**
   * Returns the PlayerSeatComposite if a player with the same id is sitting
   * at the table
   *
   * @param playerId The id of the player (must be seated at the table)
   * @return The associated {@link PlayerSeatComposite}, or <code>null</code>,
   *         if the player is not at the table
   * @throws IllegalArgumentException If no player with the given id is
   *             sitting at the table
   */
  public PlayerSeatComposite findPlayerSeatCompositeByPlayerId(PlayerId playerId)
      throws IllegalArgumentException {
    for (PlayerSeatComposite pc : getPlayerSeatComposites(true)) {
      if (pc.getPlayerId().equals(playerId)) {
        return pc;
      }
    }
    throw new IllegalArgumentException("Player with id " + playerId + " not found at table");
  }
 
  /**
   * Returns the PlayerSeatComposite for the given seat id
   *
   * @param seatId The seat id
   * @return The associated {@link PlayerSeatComposite}, or <code>null</code>,
   *         if the player is not at the table
   * @throws IllegalArgumentException If no seat with the given id is
   *             available at the table (i.e. seatId 10 for a 6-handed table)
   */
  public PlayerSeatComposite findPlayerSeatCompositeBySeatId(SeatId seatId)
      throws IllegalArgumentException {
    for (PlayerSeatComposite pc : getPlayerSeatComposites(false)) {
      if (pc.getSeatId().equals(seatId)) {
        return pc;
      }
    }
    throw new IllegalArgumentException("Seat id " + seatId + " not found at table");
  }
 
  /**
   * Updates the Progress bars to indicate who's turn it is to act
   *
   * @param playerToAct The player who's turn it is
   */
  void proceedToNextPlayer(PlayerId next) {
    for (PlayerSeatComposite pc : getPlayerSeatComposites(true)) {
      if (pc.isToAct()) {
        pc.setActive(false);
      }
    }
    findPlayerSeatCompositeByPlayerId(next).setActive(true);
  }
 
  /**
   * Move the current bets of each player into the pot via an animation
   */
  public void moveBetsToPot() {
    getPotChipsArea().setVisible(false);
    List<PlayerSeatComposite> allPlayers = getPlayerSeatComposites(true);
    List<PlayerSeatComposite> playersWithBets = new ArrayList<PlayerSeatComposite>();
   
    // Determine locations of the chip piles on the table
    for (PlayerSeatComposite pc : allPlayers) {
      if (getBetPile(pc.getPlayerId()).size() != 0) {
        playersWithBets.add(pc);
      }
    }
   
    animateChips(playersWithBets, true);
   
    // Make sure no more bets are displayed now
    // Reset all the bet piles and the display areas
    // lol redraw
    for (Canvas betArea : playerBetAreas) {
      betArea.setVisible(true);
    }
    redraw();
    update();
  }
 
  /**
   * @param onlyOccupied Whether only these {@link PlayerSeatComposite}s
   *            should be returned where a player is sitting
   * @return A list of all children player seat composites
   */
  public List<PlayerSeatComposite> getPlayerSeatComposites(boolean onlyOccupied) {
    List<PlayerSeatComposite> result = new ArrayList<PlayerSeatComposite>();
    for (Control c : getChildren()) {
      if (c instanceof PlayerSeatComposite) {
        PlayerSeatComposite pc = (PlayerSeatComposite) c;
        if (pc.getPlayerId() == null && onlyOccupied) {
          continue;
        }
        result.add(pc);
      }
    }
    return result;
  }
 
  private void animateChips(final Rectangle from, final Rectangle to) {
    logger.debug("Starting animation");
   
    final int timerInterval = 10;
    final int steps = 30;
   
    getDisplay().syncExec(new Runnable() {
     
      double i = 0;
     
      public void run() {
       
        i++;
       
        final double xStep = (double) (from.x - to.x) / steps;
        final double yStep = (double) ((from.y + from.height) - (to.y + to.height)) / steps;
        Rectangle newBounds = new Rectangle(from.x - (int) (i * xStep), from.y - (int) (i * yStep), from.width,
            from.height);
        Rectangle redrawArea = dealer.getDealerChipLocation().union(newBounds);
        from.x = newBounds.x;
        from.y = newBounds.y;
        redraw(redrawArea.x, redrawArea.y, redrawArea.width, redrawArea.height, false);
        update();
        try {
          Thread.sleep(timerInterval);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        if (i < steps) {
          getDisplay().syncExec(this);
        }
      }
    });
    // Layout to reset the locations
    layout();
  }
 
  /**
   * @param pcs
   * @param toPot
   */
  private void animateChips(final List<PlayerSeatComposite> pcs, final boolean toPot) {
    logger.debug("Starting animation");
    final int timerInterval = 10;
    final int steps = 30;
    final Canvas to = toPot ? getPotChipsArea() : pcs.get(0).getChipsArea();
   
    getDisplay().syncExec(new Runnable() {
     
      double i = 0;
     
      public void run() {
       
        i++;
       
        for (PlayerSeatComposite pc : pcs) {
          Canvas from = toPot ? pc.getChipsArea() : getPotChipsArea();
          Rectangle fromBounds = from.getBounds();
         
          Rectangle toBounds = to.getBounds();
          final double xStep = (double) (fromBounds.x - toBounds.x) / steps;
          final double yStep = (double) ((fromBounds.y + fromBounds.height) - (toBounds.y + toBounds.height))
              / steps;
         
          Rectangle newBounds = new Rectangle(fromBounds.x - (int) (i * xStep), fromBounds.y
              - (int) (i * yStep), fromBounds.width, fromBounds.height);
          Rectangle redrawArea = fromBounds.union(newBounds);
          from.setBounds(newBounds);
          redraw(redrawArea.x, redrawArea.y, redrawArea.width, redrawArea.height, false);
        }
        update();
        try {
          Thread.sleep(timerInterval);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        if (i < steps) {
          getDisplay().syncExec(this);
        }
      }
    });
    // Layout to reset the locations
    layout();
  }
 
  /**
   * @param commonCards Adds these community cards and displays them
   */
  public void addCommunityCards(Set<Card> commonCards) {
    communityCards.addAll(commonCards);
    communityCardsComposite.setVisible(true);
    communityCardsComposite.redraw();
  }
 
  /**
   * @param commonCards Adds these community cards and displays them
   */
  public void clearCommunityCards() {
    communityCards.clear();
    communityCardsComposite.redraw();
  }
 
  /**
   * Reverse method to {@link #moveBetsToPot()} TODO What if there are more
   * than one winner, the bet pile needs to be split accordingly first ...
   *
   * @param winners The winners in the hand
   */
  public void movePotsToWinners(final Collection<Winner> winners) {
    List<PlayerSeatComposite> winnerPCs = new ArrayList<PlayerSeatComposite>();
    // Ship it
    for (Winner winner : winners) {
      PlayerSeatComposite winnerPC = findPlayerSeatCompositeByPlayerId(winner.getPlayerId());
      ClientGUI.playAudio(ClientGUI.Resources.SOUND_FILE_SLIDE_CHIPS);
      winnerPCs.add(winnerPC);
     
    }
    getPotChipsArea().setVisible(true);
    //doesn't work
    animateChips(winnerPCs, false);
    redraw();
    update();
  }
 
  /**
   * @return the Composite holding the Community Card Images
   */
  public Composite getCommunityCardsComposite() {
    return communityCardsComposite;
  }
 
  public Canvas getPotChipsArea() {
    return potChipsArea;
  }
 
  /**
   * Do the actual drawing of chip images on the {@link TableComposite}
   * surface
   *
   * @param area Where the chips are to be drawn
   * @param chipPiles The chips to draw
   * @param size The desired size of the chips
   * @param putDifferentValuesOnSeparatePiles Whether you want to mix
   *            different chip values in the same pile
   */
  public void drawChips(GC gc, Rectangle area, List<NavigableMap<Chip, Integer>> chipPiles,
      boolean putDifferentValuesOnSeparatePiles, boolean dealerButton) {
    int amount = Chip.getValue(chipPiles);
    int size = 1;
    for (int i = 2; i < 7; i++) {
      Image chipImage = Chip.DEALER.getImage(i);
      int imgHeight = chipImage.getBounds().height;
      if (imgHeight + Chip.MAX_CHIPS_IN_PILE * i > area.height) {
        size = i - 1;
        break;
      }
    }
   
    if (amount == 0 && !dealerButton) {
      return;
    }
   
    int xCoord = area.x;
    int standardXDistance = Chip.DEALER.getImage(size).getBounds().width + size;
    int standardYLocation = area.y + area.height - Chip.ONE_CENT_CHIP.getImage(size).getBounds().height;
    // Iterate over the chip piles.
    for (NavigableMap<Chip, Integer> chipPile : chipPiles) {
     
      int yCoord = standardYLocation;
      int totalChips = 0;
      // Iterate over the chip pile entries
      for (Entry<Chip, Integer> entry : chipPile.entrySet()) {
       
        if (entry.getValue() == 0)
          continue;
       
        Image chipImg = entry.getKey().getImage(size);
        for (int i = 0; i < entry.getValue(); i++) {
          if (totalChips > Chip.MAX_CHIPS_IN_PILE) {
            // Once we reach the maximum, shift to the right and
            // open a new pile
            // Update the offset
            xCoord += standardXDistance;
            yCoord = standardYLocation;
            totalChips = 0;
          }
          // While there are still chips of the same value in the
          // pile, stack them on top of each other
          gc.drawImage(chipImg, xCoord, yCoord);
          yCoord -= (size + 1);
          totalChips++;
         
        }
        if (putDifferentValuesOnSeparatePiles) {
          // If we dont want chips of different values on top of each
          // other, open up a new pile before going to the next chip
          // type
          // Update the offset
          xCoord += standardXDistance;
          yCoord = standardYLocation;
          totalChips = 0;
        }
      }
      xCoord += standardXDistance;
    }
    // Annotate the chip pile image with a textual display of the bet amount
    gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
    gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
    if (!dealerButton) {
      gc.drawText(ClientGUI.formatBet(amount), xCoord, standardYLocation);
    }
    if (ClientGUI.COMPOSITE_BORDER_STYLE == SWT.BORDER)
      gc.drawRectangle(area);
    return;
  }
 
  /**
   * @param psc
   * @param findPlayerSeatCompositeByPlayerId
   */
  public void moveDealerButton(PlayerSeatComposite from, PlayerSeatComposite to) {
   
    Rectangle dealerButtonLocation = from.getDealerChipLocation();
    Rectangle toLocation = to.getDealerChipLocation();
    if (dealer != null) {
      animateChips(dealerButtonLocation, toLocation);
    }
    dealer = to;
  }
 
  /**
   * Issue a redraw of the table (when chips have moved etc.)
   */
  public void updateTableGraphics() {
    redraw();
    update();
  }
 
  private List<NavigableMap<Chip, Integer>> getBetPile(PlayerId player) {
    List<NavigableMap<Chip, Integer>> chipStacks = new ArrayList<NavigableMap<Chip, Integer>>();
    GameState gs = tableState.getGameState();
    if (gs == null) {
      logger.warn("GameState is null");
      return chipStacks;
    }
    PlayerState ps = gs.getPlayer(player);
    if (ps == null) {
      logger.warn("Player state for " + player + " is null");
      return chipStacks;
    }
    for (Integer i : ps.getBetProgression()) {
      chipStacks.add(Chip.getDistribution(i));
    }
    return chipStacks;
  }
}
TOP

Related Classes of org.cspoker.client.gui.swt.window.TableComposite

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.