gt:                 final int giveW = fm.stringWidth(giveLab2.getText()) + 1;
context: /**
   * Open Settlers - an open implementation of the game Settlers of Catan
   * Copyright (C) 2003  Robert S. Thomas
   * Portions of this file Copyright (C) 2007-2009 Jeremy D Monin <jeremy@nand.net>
   *
   * 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, see <http://www.gnu.org/licenses/>. **/
  package soc.client;
  
  import soc.game.Game;
  import soc.game.Player;
  import soc.game.ResourceSet;
  import soc.game.TradeOffer;
  
  import java.awt.Button;
  import java.awt.CardLayout;
  import java.awt.Color;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.FontMetrics;
  import java.awt.Label;
  import java.awt.Panel;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  
  
  /**
   * Two-mode panel to display either a short status message, or a
   * resource trade offer (and counter-offer).
   *<P>
   * The status message mode is used for tasks such as:
   * @version $Revision: 1.6 $
   *  <LI> Saying "no thanks" to a trade offer
   *  <LI> Showing vote on a board reset request
   *  <LI> Showing the player is deciding what to discard
   *</UL>
   *<P>
   * To set this panel's position or size, please use {@link #setBounds(int, int, int, int)},
   * because it is overridden to also update a "compact mode" flag for counter-offer layout.
   */
  public class TradeOfferPanel extends Panel
  {
      private static final long serialVersionUID = 7328841152192283316L;
      public static final String OFFER_MODE = "offer";
      public static final String MESSAGE_MODE = "message";
  
      /**
       * Typical height of offer panel, when visible. (Includes
       * {@link #OFFER_BUTTONS_HEIGHT}, but not {@link #OFFER_COUNTER_HEIGHT}.)
       * For convenience of other classes' layout calculations.
       * Actual height (buttons' y-positions + height) is set dynamically in OfferPanel.doLayout.
       * @since 1.1.08
       */
      public static final int OFFER_HEIGHT
          = (5 + 32 + (SquaresPanel.HEIGHT + 8)) + 18 + 10;
          // As calculated in OfferPanel.doLayout():
          //    top = between 5 and 18: = (h / (int)(.5 * ColorSquareLarger.HEIGHT_L)) + 5
          //    squaresHeight = squares.getBounds().height + 8
          //    buttonY = top + 32 + squaresHeight
          //    buttonH = 18
          //    inset = 10
          //    HEIGHT = buttonY + buttonH + inset
  
      /**
       * Additional height of offer (part of {@link #OFFER_HEIGHT})
       * when the "offer"/"accept"/"reject" buttons are showing.
       * That is, when not in counter-offer mode.
       * For convenience of other classes' layout calculations.
       * Based on calculations within OfferPanel.doLayout.
       * @since 1.1.08
       */
      public static final int OFFER_BUTTONS_HEIGHT = 26;
  
      /**
       * Typical height of counter-offer panel, when visible.
       * For convenience of other classes' layout calculations.
       * Actual height of counter-offer (offerBox) is set dynamically in OfferPanel.doLayout.
       * @since 1.1.08
       */
      public static final int OFFER_COUNTER_HEIGHT
          = SquaresPanel.HEIGHT + 24 + 16 + ColorSquareLarger.HEIGHT_L;
          // As calculated in OfferPanel.doLayout():
          //   squaresHeight = squares.getBounds().height + 24
          //   lineH = ColorSquareLarger.HEIGHT_L
          //   HEIGHT = squaresHeight + 16 + lineH
  
      protected static final int[] zero = { 0, 0, 0, 0, 0 };
      static final String OFFER = "counter";
      static final String ACCEPT = "accept";
      static final String REJECT = "reject";
      static final String SEND = "send";
      static final String CLEAR = "clear";
      static final String CANCEL = "cancel";
      static final Color insideBGColor = new Color(255, 230, 162);
      int from;
      HandPanel hp;
      PlayerInterface pi;
  
      String mode;
      CardLayout cardLayout;
      MessagePanel messagePanel;
      OfferPanel offerPanel;
  
      /**
       * If true, display counter-offer in a "compact mode" layout
       * because the panel's height is too short for the normal arrangement.
       * Calculated using {@link #OFFER_HEIGHT} + {@link #OFFER_COUNTER_HEIGHT}
       *     - {@link #OFFER_BUTTONS_HEIGHT}.
       * @since 1.1.08
       */
      private boolean counterCompactMode;
  
      /**
       * If true, hide the original offer's balloon point
       * (see {@link SpeechBalloon#setBalloonPoint(boolean)})
       * when the counter-offer is visible.
       * @since 1.1.08 
       */
      private boolean counterHidesBalloonPoint;
  
      /**
       * Creates a new TradeOfferPanel object.
       */
      public TradeOfferPanel(HandPanel hp, int from)
      {
          this.hp = hp;
          this.from = from;
          pi = hp.getPlayerInterface();
  
          setBackground(pi.getPlayerColor(from));
          setForeground(Color.black);
  
          messagePanel = new MessagePanel();
          offerPanel = new OfferPanel();
          
          cardLayout = new CardLayout();
          setLayout(cardLayout);
  
          add(messagePanel, MESSAGE_MODE); // first added = first shown
          add(offerPanel, OFFER_MODE);
          mode = MESSAGE_MODE;
  
          counterCompactMode = false;
          counterHidesBalloonPoint = false;
      }
      
      private class MessagePanel extends Panel
      {
          /**
           * 
           */
          private static final long serialVersionUID = -8066167179927154007L;
          SpeechBalloon balloon;
          Label msg;
          int msgHeight;
  
          /**
           * Creates a new MessagePanel object.
           */
          public MessagePanel()
          {
              setLayout(null);
              setFont(new Font("SansSerif", Font.PLAIN, 18));
          
              msg = new Label(" ", Label.CENTER);
              msg.setBackground(insideBGColor);
              msgHeight = 0;  // set in doLayout
              add(msg);
          
              balloon = new SpeechBalloon(pi.getPlayerColor(from));
              add(balloon);
          }
          
          /**
           * Update the text shown in this messagepanel.
           * Does not show or hide the panel, only changes the label text.
           * @param message message to display, or null for no text
           */
          public void update(String message)
          {
              if (message != null)
                  msg.setText(message);
              else
                  msg.setText(" ");
          }
          
          /**
           * Just for the message panel
           */
          public void doLayout()
          {
              Dimension dim = getSize();
              int buttonW = 48;
              int inset = 10;
              if (msgHeight == 0)
                  msgHeight = getFontMetrics(msg.getFont()).getHeight() + 4;
              int w = Math.min((2*(inset+5) + 3*buttonW), dim.width);
              int h = Math.min(92 + 2 * ColorSquareLarger.HEIGHT_L, dim.height);
              int msgY = (h - msgHeight) / 2;
              if (msgY < 0)
                  msgY = 0;
              if (msgHeight > h)
                  msgHeight = h;
              msg.setBounds(inset, msgY, w - (2 * inset), msgHeight);
              balloon.setBounds(0, 0, w, h);
          }
      }
  
      /** Contains both offer and counter-offer; see {@link #setCounterOfferVisible(boolean)} */
      private class OfferPanel extends Panel implements ActionListener
      {
          /**
           * 
           */
          private static final long serialVersionUID = -8055790775282788045L;
  
          /** Balloon to hold offer received */
          SpeechBalloon balloon;
  
          /** "Offered To" line 1 */
          Label toWhom1;
          /** "Offered To" line 2 for wrapping; usually blank */
          Label toWhom2;
          /** "I Give" */
          Label giveLab;
          /** "I Get" */
          Label getLab;
  
          /** Offer's resources */
          SquaresPanel squares;
          /** send button for counter-offer */
          Button offerBut;
          Button acceptBut;
          Button rejectBut;
  
          /** Counter-offer to send */
          ShadowedBox offerBox;
          Label counterOfferToWhom;
          boolean counterOffer_playerInit = false;
          SquaresPanel offerSquares;
          Label giveLab2;
          Label getLab2;
          Button sendBut;
          Button clearBut;
          Button cancelBut;
          boolean offered;
          ResourceSet give;
          ResourceSet get;
          int[] giveInt = new int[5];
          int[] getInt = new int[5];
  
          /** is the counter-offer showing? use {@link #setCounterOfferVisible(boolean)} to change. */
          boolean counterOfferMode = false;
  
          /**
           * Creates a new OfferPanel object.
           * The counter-offer is initially hidden.
           */
          public OfferPanel()
          {
              setLayout(null);
              setFont(new Font("SansSerif", Font.PLAIN, 10));
  
              /** Offer received */
  
              toWhom1 = new Label();
              toWhom1.setBackground(insideBGColor);
              add(toWhom1);
  
              toWhom2 = new Label();
              toWhom2.setBackground(insideBGColor);
              add(toWhom2);
  
              /** Offer's resources */
              squares = new SquaresPanel(false);
              add(squares);
  
              giveLab = new Label("I Give: ");
              giveLab.setBackground(insideBGColor);
              add(giveLab);
              new AWTToolTip("Opponent gives to you", giveLab);
  
              getLab = new Label("I Get: ");
              getLab.setBackground(insideBGColor);
              add(getLab);
              new AWTToolTip("You give to opponent", getLab);
  
              giveInt = new int[5];
              getInt = new int[5];
  
              acceptBut = new Button("Accept");
              acceptBut.setActionCommand(ACCEPT);
              acceptBut.addActionListener(this);
              add(acceptBut);
  
              rejectBut = new Button("Reject");
              rejectBut.setActionCommand(REJECT);
              rejectBut.addActionListener(this);
              add(rejectBut);
  
              offerBut = new Button("Counter");
              offerBut.setActionCommand(OFFER);
              offerBut.addActionListener(this);
              add(offerBut);
  
              /** Counter-offer to send */
  
              counterOfferToWhom = new Label();
              counterOfferToWhom.setVisible(false);
              add(counterOfferToWhom);
  
              sendBut = new Button("Send");
              sendBut.setActionCommand(SEND);
              sendBut.addActionListener(this);
              sendBut.setVisible(false);
              add(sendBut);
  
              clearBut = new Button("Clear");
              clearBut.setActionCommand(CLEAR);
              clearBut.addActionListener(this);
              clearBut.setVisible(false);
              add(clearBut);
  
              cancelBut = new Button("Cancel");
              cancelBut.setActionCommand(CANCEL);
              cancelBut.addActionListener(this);
              cancelBut.setVisible(false);
              add(cancelBut);
  
              offerSquares = new SquaresPanel(true);
              offerSquares.setVisible(false);
              add(offerSquares);
  
              giveLab2 = new Label("Give Them: ");
              giveLab2.setVisible(false);
              add(giveLab2);
              new AWTToolTip("Give to opponent", giveLab2);
  
              getLab2 = new Label("You Get: ");
              getLab2.setVisible(false);
              add(getLab2);
              new AWTToolTip("Opponent gives to you", getLab2);
  
              // correct the interior when we can get our player color
              offerBox = new ShadowedBox(pi.getPlayerColor(from), Color.white);
              offerBox.setVisible(false);
              add(offerBox);
  
              /** done with counter-offer */
  
              balloon = new SpeechBalloon(pi.getPlayerColor(from));
              add(balloon);
          }
  
          /**
           * Update the displayed offer.
           * Should be called when already in {@link TradeOfferPanel#OFFER_MODE},
           * or about to switch to it via {@link TradeOfferPanel#setOffer(TradeOffer)}.
           *
           * @param  offer  the trade offer, with set of resources being given and asked for
           */
          public void update(TradeOffer offer)
          {
              this.give = offer.getGiveSet();
              this.get = offer.getGetSet();
              boolean[] offerList = offer.getTo();
          
              Player player = hp.getGame().getPlayer(hp.getClient().getNickname());
  
              if (player != null)
              {
                  if (! counterOffer_playerInit)
                  {
                      // do we have to fill in opponent's name for 1st time,
                      // and set up colors?
                      Color ourPlayerColor = pi.getPlayerColor(player.getPlayerNumber());
                      giveLab2.setBackground(ourPlayerColor);
                      getLab2.setBackground(ourPlayerColor);
                      counterOfferToWhom.setBackground(ourPlayerColor);
                      offerBox.setInterior(ourPlayerColor);
                      counterOfferToWhom.setText
                          ("Counter to " + hp.getPlayer().getName() + ":");
  
                      counterOffer_playerInit = true;
                  }                
                  offered = offerList[player.getPlayerNumber()];
              }
              else
              {
                  offered = false;
              }
          
              Game ga = hp.getGame();
              final int maxChars = (ga.maxPlayers > 4) ? 30 : 25;
              String names1 = "Offered to: ";
              String names2 = null;
  
              int cnt = 0;
  
              for (; cnt < ga.maxPlayers; cnt++)
              {
                  if (offerList[cnt] && ! ga.isSeatVacant(cnt))
                  {
                      names1 += ga.getPlayer(cnt).getName();
  
                      break;
                  }
              }
  
              cnt++;
  
              int len = names1.length();
  
              for (; cnt < ga.maxPlayers; cnt++)
              {
                  if (offerList[cnt] && ! ga.isSeatVacant(cnt))
                  {
                      String name = ga.getPlayer(cnt).getName();
                      len += name.length();  // May be null if vacant
                      
                      if (len < maxChars)
                      {
                          names1 += ", ";
                          names1 += name;
                      }
                      else
                      {
                          if (names2 == null)
                          {
                              names1 += ",";
                              names2 = name;
                          }
                          else
                          {
                              names2 += ", ";
                              names2 += name;
                          }
                      }
                  }
              }
              toWhom1.setText(names1);
              toWhom2.setText(names2);
  
              /**
               * Note: this only works if ResourceConstants.CLAY == 1
               */
              for (int i = 0; i < 5; i++)
              {
                  giveInt[i] = give.getAmount(i + 1);
                  getInt[i] = get.getAmount(i + 1);
              }
              squares.setValues(giveInt, getInt);
  
              // enables accept,reject,offer Buttons if 'offered' is true
              setCounterOfferVisible(counterOfferMode);
              validate();
          }
  
          /**
           * Custom layout for this OfferPanel
           */
          public void doLayout()
          {
              FontMetrics fm = this.getFontMetrics(this.getFont());
              Dimension dim = getSize();
              final int buttonW = 48;
              final int buttonH = 18;
              int inset = 10;
  
              // At initial call to doLayout: dim.width, .height == 0.
              int w = Math.min((2*(inset+5) + 3*buttonW), dim.width);
              int h = Math.min(92 + 2 * ColorSquareLarger.HEIGHT_L, dim.height);
              int top = (h / (int)(.5 * ColorSquareLarger.HEIGHT_L)) + 5;
  
              if (counterOfferMode)
              {
                  // show the counter offer controls
  
                  final int lineH = ColorSquareLarger.HEIGHT_L;
                  h = Math.min(60 + 2 * ColorSquareLarger.HEIGHT_L, h);
                  top = (h / (int)(.5 * ColorSquareLarger.HEIGHT_L)) + 10;
  
                  if (counterCompactMode)
                  {
                      inset = 2;
                      balloon.setBalloonPoint(false);
                      top -= (h / 8);  // Shift everything up this far, since we
                                       // don't need to leave room for balloon point.
                  } else {
                      balloon.setBalloonPoint(! counterHidesBalloonPoint);
                  }
  
  