/******************************************************************************* * 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 3 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 org.worldgrower.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Image; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTextPane; import javax.swing.SpringLayout; import org.worldgrower.Constants; import org.worldgrower.LogMessage; import org.worldgrower.ManagedOperation; import org.worldgrower.ManagedOperationListener; import org.worldgrower.TargetKnowsAction; import org.worldgrower.World; import org.worldgrower.WorldObject; import org.worldgrower.goal.EnergyPropertyUtils; import org.worldgrower.gui.music.SoundIdReader; import org.worldgrower.gui.status.StatusMessage; import org.worldgrower.gui.status.StatusMessageDialog; import org.worldgrower.gui.util.JTextPaneFactory; import org.worldgrower.gui.util.JTextPaneUtils; public final class InfoPanel extends JPanel { private static final String ENERGY_TOOL_TIP = "energy"; private static final String WATER_TOOL_TIP = "water"; private static final String FOOD_TOOL_TIP = "food"; private static final String HIT_POINTS_TOOL_TIP = "hit points"; private final WorldObject playerCharacter; private final World world; private final JFrame parentFrame; private final ImageInfoReader imageInfoReader; private final SoundIdReader soundIdReader; private final ImageFactory imageFactory; private final ImageSubstituter imageSubstituter; private final JTextPane messageTextPane; private final JProgressBar hitPointsProgressBar; private final JProgressBar foodTextProgressBar; private final JProgressBar waterProgressBar; private final JProgressBar energyProgressBar; private final List<StatusMessage> statusMessages = new ArrayList<>(); private int lastMessageTurn = -1; private boolean moreMessageDisplayed = false; public InfoPanel(WorldObject playerCharacter, World world, ImageInfoReader imageInfoReader, SoundIdReader soundIdReader, String initialStatusMessage, JFrame parentFrame, ImageFactory imageFactory) throws IOException { super(new BorderLayout()); setBackground(Color.RED); SpringLayout layout = new SpringLayout(); setLayout(layout); makeUnfocussable(this); this.imageFactory = imageFactory; this.imageInfoReader = imageInfoReader; this.soundIdReader = soundIdReader; this.playerCharacter = playerCharacter; this.world = world; this.parentFrame = parentFrame; this.imageSubstituter = new ImageSubstituter(imageInfoReader); messageTextPane = JTextPaneFactory.createJTextPane(imageInfoReader); messageTextPane.setEditable(false); int messageWidth = 600; int messageHeight = 80; messageTextPane.setMinimumSize(new Dimension(messageWidth, messageHeight)); messageTextPane.setPreferredSize(new Dimension(messageWidth, messageHeight)); setStatusMessage(initialStatusMessage); messageTextPane.setToolTipText("This area displays messages like combat or dialogues. Click to show previous messages."); makeUnfocussable(messageTextPane); messageTextPane.addMouseListener(new MessageTextAreaMouseListener()); world.addListener(new MessageManagedOperationListener()); hitPointsProgressBar = new TiledVerticalImageProgressBar(0, playerCharacter.getProperty(Constants.HIT_POINTS_MAX), ImageIds.HEALTH_BACKGROUND, imageInfoReader); hitPointsProgressBar.setBackground(Color.BLACK); hitPointsProgressBar.setForeground(Color.RED); hitPointsProgressBar.setToolTipText(HIT_POINTS_TOOL_TIP); makeUnfocussable(hitPointsProgressBar); add(hitPointsProgressBar); layout.putConstraint(SpringLayout.WEST, hitPointsProgressBar, 0, SpringLayout.EAST, messageTextPane); layout.putConstraint(SpringLayout.NORTH, hitPointsProgressBar, 0, SpringLayout.NORTH, messageTextPane); layout.putConstraint(SpringLayout.SOUTH, hitPointsProgressBar, 0, SpringLayout.SOUTH, messageTextPane); foodTextProgressBar = new TiledVerticalImageProgressBar(0, 1000, ImageIds.FOOD_BACKGROUND, imageInfoReader); foodTextProgressBar.setBackground(Color.BLACK); foodTextProgressBar.setForeground(Color.YELLOW); foodTextProgressBar.setToolTipText(FOOD_TOOL_TIP); makeUnfocussable(foodTextProgressBar); add(foodTextProgressBar); layout.putConstraint(SpringLayout.WEST, foodTextProgressBar, 0, SpringLayout.EAST, hitPointsProgressBar); layout.putConstraint(SpringLayout.NORTH, foodTextProgressBar, 0, SpringLayout.NORTH, hitPointsProgressBar); layout.putConstraint(SpringLayout.SOUTH, foodTextProgressBar, 0, SpringLayout.SOUTH, messageTextPane); waterProgressBar = new TiledVerticalImageProgressBar(0, 1000, ImageIds.WATER_BACKGROUND, imageInfoReader); waterProgressBar.setBackground(Color.BLACK); waterProgressBar.setForeground(Color.BLUE); waterProgressBar.setToolTipText(WATER_TOOL_TIP); makeUnfocussable(waterProgressBar); add(waterProgressBar); layout.putConstraint(SpringLayout.WEST, waterProgressBar, 0, SpringLayout.EAST, foodTextProgressBar); layout.putConstraint(SpringLayout.NORTH, waterProgressBar, 0, SpringLayout.NORTH, foodTextProgressBar); layout.putConstraint(SpringLayout.SOUTH, waterProgressBar, 0, SpringLayout.SOUTH, messageTextPane); energyProgressBar = new TiledVerticalImageProgressBar(0, EnergyPropertyUtils.calculateEnergyMax(playerCharacter), ImageIds.ENERGY_BACKGROUND, imageInfoReader); energyProgressBar.setBackground(Color.BLACK); energyProgressBar.setForeground(Color.GREEN); energyProgressBar.setToolTipText(ENERGY_TOOL_TIP); makeUnfocussable(energyProgressBar); add(energyProgressBar); layout.putConstraint(SpringLayout.WEST, energyProgressBar, 0, SpringLayout.EAST, waterProgressBar); layout.putConstraint(SpringLayout.NORTH, energyProgressBar, 0, SpringLayout.NORTH, waterProgressBar); layout.putConstraint(SpringLayout.SOUTH, energyProgressBar, 0, SpringLayout.SOUTH, messageTextPane); add(messageTextPane); layout.putConstraint(SpringLayout.WEST, messageTextPane, 0, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.NORTH, messageTextPane, 0, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.EAST, this, 0, SpringLayout.EAST, energyProgressBar); layout.putConstraint(SpringLayout.SOUTH, this, 0, SpringLayout.SOUTH, messageTextPane); } private class MessageManagedOperationListener implements ManagedOperationListener { @Override public void actionPerformed(ManagedOperation managedOperation, WorldObject performer, WorldObject target, int[] args, Object message) { if (performer.equals(playerCharacter) || target.equals(playerCharacter)) { if (message instanceof String) { if (target.equals(playerCharacter)) { setStatusMessage(imageFactory.getImage(performer), (String) message); } else { setStatusMessage(imageFactory.getImage(target), (String) message); } } else if (message instanceof LogMessage) { LogMessage logMessage = (LogMessage) message; if (target.equals(playerCharacter)) { if (logMessage.getTargetKnowsAction() == TargetKnowsAction.TRUE) { setStatusMessage(imageFactory.getImage(performer), logMessage.getMessage()); } } else { setStatusMessage(imageFactory.getImage(target), logMessage.getMessage()); } } } } } public void setStatusMessage(String message) { int currentTurn = world.getCurrentTurn().getValue(); if (lastMessageTurn == currentTurn) { appendNoMoreMessages(); } else { clearMessageTextPane(); displayMessage(message); } statusMessages.add(new StatusMessage(null, message)); lastMessageTurn = currentTurn; } private void clearMessageTextPane() { moreMessageDisplayed = false; messageTextPane.setText(""); } private void appendNoMoreMessages() { if (!moreMessageDisplayed) { moreMessageDisplayed = true; JTextPaneUtils.appendIconAndText(messageTextPane, imageFactory.getMoreMessagesImage(), "More messages..."); } } public void setStatusMessage(Image image, String message) { int currentTurn = world.getCurrentTurn().getValue(); if (lastMessageTurn == currentTurn) { appendNoMoreMessages(); } else { clearMessageTextPane(); displayMessage(image, message); } statusMessages.add(new StatusMessage(image, message)); lastMessageTurn = currentTurn; } private void displayMessage(String text) { imageSubstituter.subtituteImagesInTextPane(messageTextPane, text); } private void displayMessage(Image image, String message) { JTextPaneUtils.appendIcon(messageTextPane, image); imageSubstituter.subtituteImagesInTextPane(messageTextPane, message); } public void clearStatusMessages() { clearMessageTextPane(); lastMessageTurn = -1; } private void makeUnfocussable(JComponent component) { component.setRequestFocusEnabled(false); component.setFocusable(false); } private class MessageTextAreaMouseListener extends MouseAdapter { @Override public void mouseClicked(MouseEvent event) { showStatusMessageDialog(); } } public void showStatusMessageDialog() { new StatusMessageDialog(statusMessages, imageInfoReader, soundIdReader, parentFrame).showMe(); } public void updatePlayerCharacterValues() { hitPointsProgressBar.setValue(playerCharacter.getProperty(Constants.HIT_POINTS)); foodTextProgressBar.setValue(playerCharacter.getProperty(Constants.FOOD)); waterProgressBar.setValue(playerCharacter.getProperty(Constants.WATER)); energyProgressBar.setValue(playerCharacter.getProperty(Constants.ENERGY)); updateToolTips(); } private void updateToolTips() { hitPointsProgressBar.setToolTipText(HIT_POINTS_TOOL_TIP + " " + playerCharacter.getProperty(Constants.HIT_POINTS) + "/" + playerCharacter.getProperty(Constants.HIT_POINTS_MAX)); foodTextProgressBar.setToolTipText(FOOD_TOOL_TIP + " " + playerCharacter.getProperty(Constants.FOOD) + "/1000"); waterProgressBar.setToolTipText(WATER_TOOL_TIP + " " + playerCharacter.getProperty(Constants.WATER) + "/1000"); energyProgressBar.setToolTipText(ENERGY_TOOL_TIP + " " + playerCharacter.getProperty(Constants.ENERGY) + "/" + EnergyPropertyUtils.calculateEnergyMax(playerCharacter)); } }