/*
* $Id$
*
* Copyright (c) 2000-2003 by Rodney Kinney
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.counters;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.command.ChangeTracker;
import VASSAL.command.Command;
import VASSAL.configure.ColorConfigurer;
import VASSAL.configure.IntConfigurer;
import VASSAL.configure.NamedHotKeyConfigurer;
import VASSAL.configure.PieceAccessConfigurer;
import VASSAL.i18n.PieceI18nData;
import VASSAL.i18n.TranslatablePiece;
import VASSAL.tools.NamedKeyStroke;
import VASSAL.tools.SequenceEncoder;
public class Hideable extends Decorator implements TranslatablePiece {
public static final String ID = "hide;";
public static final String HIDDEN_BY = "hiddenBy";
public static final String TRANSPARENCY = "transparency";
protected String hiddenBy;
protected NamedKeyStroke hideKey;
protected String command = "Invisible";
protected PieceAccess access = PlayerAccess.getInstance();
protected float transparency = 0.3f;
protected Color bgColor;
protected KeyCommand[] commands;
protected KeyCommand hideCommand;
public void setProperty(Object key, Object val) {
if (HIDDEN_BY.equals(key)) {
hiddenBy = (String) val;
}
else {
super.setProperty(key, val);
}
}
@Override
public Object getLocalizedProperty(Object key) {
if (invisibleToMe()) {
return ((BasicPiece) Decorator.getInnermost(this)).getLocalizedPublicProperty(key);
}
else if (HIDDEN_BY.equals(key)) {
return hiddenBy;
}
else if (Properties.INVISIBLE_TO_ME.equals(key)) {
return invisibleToMe() ? Boolean.TRUE : Boolean.FALSE;
}
else if (Properties.INVISIBLE_TO_OTHERS.equals(key)) {
return invisibleToOthers() ? Boolean.TRUE : Boolean.FALSE;
}
else if (Properties.VISIBLE_STATE.equals(key)) {
return String.valueOf(invisibleToOthers()) +
invisibleToMe() + piece.getProperty(key);
}
else {
return super.getLocalizedProperty(key);
}
}
public Object getProperty(Object key) {
if (HIDDEN_BY.equals(key)) {
return hiddenBy;
}
else if (Properties.INVISIBLE_TO_ME.equals(key)) {
return invisibleToMe() ? Boolean.TRUE : Boolean.FALSE;
}
else if (Properties.INVISIBLE_TO_OTHERS.equals(key)) {
return invisibleToOthers() ? Boolean.TRUE : Boolean.FALSE;
}
else if (Properties.VISIBLE_STATE.equals(key)) {
return String.valueOf(invisibleToOthers()) +
invisibleToMe() + piece.getProperty(key);
}
else {
return super.getProperty(key);
}
}
public Hideable() {
this(ID + "I", null);
}
public Hideable(String type, GamePiece p) {
setInner(p);
mySetType(type);
}
public void mySetType(String type) {
SequenceEncoder.Decoder st = new SequenceEncoder.Decoder(type, ';');
st.nextToken();
hideKey = st.nextNamedKeyStroke('I');
command = st.nextToken("Invisible");
bgColor = st.nextColor(null);
access = PieceAccessConfigurer.decode(st.nextToken(null));
transparency = st.hasMoreTokens() ? (float) st.nextDouble(0.3) : 0.3f;
commands = null;
}
public void mySetState(String in) {
hiddenBy = "null".equals(in) ? null : in;
}
public String myGetType() {
final SequenceEncoder se = new SequenceEncoder(';');
se.append(hideKey)
.append(command)
.append(bgColor)
.append(PieceAccessConfigurer.encode(access))
.append(transparency);
return ID + se.getValue();
}
public String myGetState() {
return hiddenBy == null ? "null" : hiddenBy;
}
public boolean invisibleToMe() {
return !access.currentPlayerHasAccess(hiddenBy);
}
public boolean invisibleToOthers() {
return hiddenBy != null;
}
public Shape getShape() {
if (invisibleToMe()) {
return new Rectangle();
}
else {
return piece.getShape();
}
}
public Rectangle boundingBox() {
if (invisibleToMe()) {
return new Rectangle();
}
else {
return piece.boundingBox();
}
}
public void draw(Graphics g, int x, int y, Component obs, double zoom) {
if (invisibleToMe()) {
return;
}
else if (invisibleToOthers()) {
final Graphics2D g2d = (Graphics2D) g;
if (bgColor != null) {
g.setColor(bgColor);
final AffineTransform t = AffineTransform.getScaleInstance(zoom, zoom);
t.translate(x / zoom, y / zoom);
g2d.fill(t.createTransformedShape(piece.getShape()));
}
final Composite oldComposite = g2d.getComposite();
g2d.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency)
);
piece.draw(g, x, y, obs, zoom);
g2d.setComposite(oldComposite);
}
else {
piece.draw(g, x, y, obs, zoom);
}
}
public String getName() {
if (invisibleToMe()) {
return "";
}
else if (invisibleToOthers()) {
return piece.getName() + "(" + command + ")";
}
else {
return piece.getName();
}
}
public KeyCommand[] myGetKeyCommands() {
if (commands == null) {
hideCommand = new KeyCommand(command, hideKey, Decorator.getOutermost(this), this);
if (command.length() > 0 && hideKey != null && ! hideKey.isNull()) {
commands = new KeyCommand[] {hideCommand};
}
else {
commands = new KeyCommand[0];
}
}
hideCommand.setEnabled(access.currentPlayerCanModify(hiddenBy));
return commands;
}
public Command myKeyEvent(KeyStroke stroke) {
myGetKeyCommands();
if (hideCommand.matches(stroke)) {
ChangeTracker tracker = new ChangeTracker(this);
if (invisibleToOthers()) {
hiddenBy = null;
}
else if (!invisibleToMe()) {
hiddenBy = access.getCurrentPlayerId();
}
return tracker.getChangeCommand();
}
return null;
}
public String getDescription() {
return "Invisible";
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("Hideable.htm");
}
public PieceEditor getEditor() {
return new Ed(this);
}
/**
* If true, then all hidden pieces are considered invisible to all players.
* Used to temporarily draw pieces as they appear to other players
*
* @param allHidden
* @deprecated
*/
@Deprecated
public static void setAllHidden(boolean allHidden) {
if (allHidden) {
PieceAccess.GlobalAccess.hideAll();
}
else {
PieceAccess.GlobalAccess.revertAll();
}
}
public PieceI18nData getI18nData() {
return getI18nData(command, "Hide command");
}
/**
* Return Property names exposed by this trait
*/
public List<String> getPropertyNames() {
ArrayList<String> l = new ArrayList<String>();
l.add(Properties.INVISIBLE_TO_OTHERS);
return l;
}
protected static class Ed implements PieceEditor {
protected NamedHotKeyConfigurer hideKeyInput;
protected JTextField hideCommandInput;
protected ColorConfigurer colorConfig;
protected IntConfigurer transpConfig;
protected PieceAccessConfigurer accessConfig;
protected JPanel controls;
public Ed(Hideable p) {
controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
hideKeyInput = new NamedHotKeyConfigurer(null, "Keyboard command: ", p.hideKey);
controls.add(hideKeyInput.getControls());
Box b = Box.createHorizontalBox();
hideCommandInput = new JTextField(16);
hideCommandInput.setMaximumSize(hideCommandInput.getPreferredSize());
hideCommandInput.setText(p.command);
b.add(new JLabel("Menu Text: "));
b.add(hideCommandInput);
controls.add(b);
colorConfig = new ColorConfigurer(null, "Background color: ", p.bgColor);
controls.add(colorConfig.getControls());
transpConfig = new IntConfigurer(null, "Transparency (%): ", (int) (p.transparency * 100));
controls.add(transpConfig.getControls());
accessConfig = new PieceAccessConfigurer(null, "Can by hidden by: ", p.access);
controls.add(accessConfig.getControls());
}
public String getState() {
return "null";
}
public String getType() {
SequenceEncoder se = new SequenceEncoder(';');
se.append(hideKeyInput.getValueString())
.append(hideCommandInput.getText())
.append(
colorConfig.getValue() == null ? "" : colorConfig.getValueString()
)
.append(accessConfig.getValueString())
.append(transpConfig.getIntValue(30) / 100.0f);
return ID + se.getValue();
}
public Component getControls() {
return controls;
}
}
}