package games.strategy.triplea.ui; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import games.strategy.engine.data.GameData; import games.strategy.engine.data.Unit; import games.strategy.triplea.TripleAUnit; import games.strategy.ui.ScrollableTextField; import games.strategy.ui.ScrollableTextFieldListener; import games.strategy.util.IntegerMap; import games.strategy.util.Triple; /** * For when you do not want things condensed into categories. * * <p> * This creates a panel which shows a group of units individually, and lets you put points/hits towards each unit * individually. * It lets you set a max number of points total (though max per unit is not allowed yet). It can return an IntegerMap * with the points per * unit. * </p> */ public class IndividualUnitPanel extends JPanel { private static final long serialVersionUID = -4222938655315991715L; private final List<SingleUnitPanel> m_entries = new ArrayList<>(); private final JTextArea m_title; private int m_max = -1; private final JLabel m_leftToSelect = new JLabel(); private final GameData m_data; private final IUIContext m_uiContext; private ScrollableTextField m_textFieldPurelyForListening; private final ScrollableTextFieldListener m_countOptionalTextFieldListener; private final boolean m_showSelectAll; private final ScrollableTextFieldListener m_textFieldListener = field -> updateLeft(); /** * For when you do not want things condensed into categories. * This creates a panel which shows a group of units individually, and lets you put points/hits towards each unit * individually. * It lets you set a max number of points total (though max per unit is not allowed yet). It can return an IntegerMap * with the points per * unit. */ public IndividualUnitPanel(final Collection<Unit> units, final String title, final GameData data, final IUIContext uiContext, final int max, final boolean showMinAndMax, final boolean showSelectAll, final ScrollableTextFieldListener optionalListener) { m_data = data; m_uiContext = uiContext; m_title = new JTextArea(title); m_title.setBackground(this.getBackground()); m_title.setEditable(false); // m_title.setColumns(15); m_title.setWrapStyleWord(true); m_countOptionalTextFieldListener = optionalListener; setMaxAndShowMaxButton(max); m_showSelectAll = showSelectAll; for (final Unit u : units) { m_entries.add(new SingleUnitPanel(u, m_data, m_uiContext, m_textFieldListener, m_max, 0, showMinAndMax)); } layoutEntries(); } /** * For when you do not want things condensed into categories. * This creates a panel which shows a group of units individually, and lets you put points/hits towards each unit * individually. * It lets you set a max number of points total AND per unit. It can return an IntegerMap with the points per unit. * * @param unitsAndTheirMaxMinAndCurrent * mapped to their individual max, then min, then current values */ public IndividualUnitPanel(final HashMap<Unit, Triple<Integer, Integer, Integer>> unitsAndTheirMaxMinAndCurrent, final String title, final GameData data, final IUIContext context, final int max, final boolean showMinAndMax, final boolean showSelectAll, final ScrollableTextFieldListener optionalListener) { m_data = data; m_uiContext = context; m_title = new JTextArea(title); m_title.setBackground(this.getBackground()); m_title.setEditable(false); // m_title.setColumns(15); m_title.setWrapStyleWord(true); m_countOptionalTextFieldListener = optionalListener; setMaxAndShowMaxButton(max); m_showSelectAll = showSelectAll; for (final Entry<Unit, Triple<Integer, Integer, Integer>> entry : unitsAndTheirMaxMinAndCurrent.entrySet()) { final int unitMax = entry.getValue().getFirst(); int thisMax; if (m_max < 0 && unitMax < 0) { thisMax = -1; } else if (unitMax < 0) { thisMax = m_max; } else if (m_max < 0) { thisMax = unitMax; } else { thisMax = Math.min(m_max, unitMax); } final int thisMin = Math.max(0, entry.getValue().getSecond()); final int thisCurrent = Math.max(thisMin, Math.min(thisMax, entry.getValue().getThird())); m_entries.add(new SingleUnitPanel(entry.getKey(), m_data, m_uiContext, m_textFieldListener, thisMax, thisMin, thisCurrent, showMinAndMax)); } layoutEntries(); } private void setMaxAndShowMaxButton(final int max) { m_max = max; m_textFieldPurelyForListening = new ScrollableTextField(0, 0); m_textFieldListener.changedValue(null); if (m_countOptionalTextFieldListener != null) { m_textFieldPurelyForListening.addChangeListener(m_countOptionalTextFieldListener); } } public void setTitle(final String title) { m_title.setText(title); } public int getMax() { return m_max; } public void setMaxAndUpdate(final int newMax) { m_max = newMax; updateLeft(); m_textFieldPurelyForListening.setValue(0); } private void updateLeft() { if (m_max == -1) { return; } final int selected = getSelectedCount(); final int newMax = m_max - selected; for (final SingleUnitPanel entry : m_entries) { final int current = entry.getCount(); final int maxForThis = current + newMax; entry.setMax(maxForThis); } m_leftToSelect.setText("Left to select:" + newMax); m_textFieldPurelyForListening.setValue(0); } protected int getSelectedCount() { int selected = 0; for (final SingleUnitPanel entry : m_entries) { selected += entry.getCount(); } return selected; } private void layoutEntries() { this.setLayout(new GridBagLayout()); final Insets nullInsets = new Insets(0, 0, 0, 0); final Dimension buttonSize = new Dimension(80, 20); final JButton m_selectNoneButton = new JButton("None"); m_selectNoneButton.setPreferredSize(buttonSize); final JButton m_autoSelectButton = new JButton("Max"); m_autoSelectButton.setPreferredSize(buttonSize); add(m_title, new GridBagConstraints(0, 0, 7, 1, 0, 0.5, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, nullInsets, 0, 0)); m_selectNoneButton.addActionListener(e -> selectNone()); m_autoSelectButton.addActionListener(e -> autoSelect()); int yIndex = 1; for (final SingleUnitPanel entry : m_entries) { entry.createComponents(this, yIndex); yIndex++; } if (m_showSelectAll) { add(m_autoSelectButton, new GridBagConstraints(0, yIndex, 7, 1, 0, 0.5, GridBagConstraints.EAST, GridBagConstraints.NONE, nullInsets, 0, 0)); yIndex++; } add(m_leftToSelect, new GridBagConstraints(0, yIndex, 5, 2, 0, 0.5, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, nullInsets, 0, 0)); } public IntegerMap<Unit> getSelected() { final IntegerMap<Unit> selectedUnits = new IntegerMap<>(); for (final SingleUnitPanel entry : m_entries) { selectedUnits.put(entry.getUnit(), entry.getCount()); } return selectedUnits; } protected void selectNone() { for (final SingleUnitPanel entry : m_entries) { entry.selectNone(); } } protected void autoSelect() { if (m_max == -1) { for (final SingleUnitPanel entry : m_entries) { entry.selectAll(); } } else { int leftToSelect = m_max - getSelectedCount(); for (final SingleUnitPanel entry : m_entries) { final int leftToSelectForCurrent = leftToSelect + entry.getCount(); final int canSelect = entry.getMax(); if (leftToSelectForCurrent >= canSelect) { entry.selectAll(); leftToSelect -= canSelect; } else { entry.setCount(leftToSelectForCurrent); leftToSelect = 0; break; } } } } } class SingleUnitPanel extends JPanel { private static final long serialVersionUID = 5034287842323633030L; private final Unit m_unit; private final ScrollableTextField m_textField; private static Insets nullInsets = new Insets(0, 0, 0, 0); private final ScrollableTextFieldListener m_countTextFieldListener; public SingleUnitPanel(final Unit unit, final GameData data, final IUIContext uiContext, final ScrollableTextFieldListener textFieldListener, final int max, final int min, final boolean showMaxAndMin) { this(unit, data, uiContext, textFieldListener, max, min, 0, showMaxAndMin); } public SingleUnitPanel(final Unit unit, final GameData data, final IUIContext context, final ScrollableTextFieldListener textFieldListener, final int max, final int min, final int currentValue, final boolean showMaxAndMin) { m_unit = unit; final GameData m_data = data; final IUIContext m_context = context; m_countTextFieldListener = textFieldListener; m_textField = new ScrollableTextField(0, 512); if (max >= 0) { setMax(max); } setMin(min); m_textField.setShowMaxAndMin(showMaxAndMin); final TripleAUnit taUnit = TripleAUnit.get(unit); setCount(currentValue); setLayout(new GridBagLayout()); final boolean isDamaged = taUnit.getUnitDamage() > 0 || taUnit.getHits() > 0; final JLabel label = m_context.createUnitImageJLabel(m_unit.getType(), m_unit.getOwner(), m_data, isDamaged ? IUIContext.UnitDamage.DAMAGED : IUIContext.UnitDamage.NOT_DAMAGED, taUnit.getDisabled() ? IUIContext.UnitEnable.DISABLED : IUIContext.UnitEnable.ENABLED); add(label, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 10), 0, 0)); add(m_textField, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); } public int getCount() { return m_textField.getValue(); } public void setCount(final int value) { m_textField.setValue(value); } public void selectAll() { m_textField.setValue(m_textField.getMax()); } public void selectNone() { m_textField.setValue(0); } public void setMax(final int value) { m_textField.setMax(value); } public int getMax() { return m_textField.getMax(); } public void setMin(final int value) { m_textField.setMin(value); } public Unit getUnit() { return m_unit; } public void createComponents(final JPanel panel, final int yIndex) { panel.add(this, new GridBagConstraints(0, yIndex, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, nullInsets, 0, 0)); m_textField.addChangeListener(m_countTextFieldListener); } }