package jrummikub.view.impl; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import java.awt.Polygon; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollBar; import javax.swing.JViewport; import javax.swing.SwingConstants; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.border.MatteBorder; import jrummikub.model.GameSettings; import jrummikub.model.IPlayer; import jrummikub.model.Player; import jrummikub.model.PlayerSettings; import jrummikub.view.ISidePanel; @SuppressWarnings("serial") class SidePanel extends JPanel implements ISidePanel { // private InfoPanel infoPanel; private PlayerListPanel playerListPanel; private BottomScrollPane playerListScrollPane; private JLabel initialMeldLabel; private JLabel setNumberLabel; private JLabel highestValueLabel; private JLabel handStonesLabel; private JLabel jokerLabel; private JLabel noLimitsLabel; private JLabel colorLabel; private JProgressBar heapBar; private GameSettings gameSettings; public SidePanel() { setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); InfoPanel infoPanel = new InfoPanel(createGameInfoPanel(), createRuleInfoPanel()); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; infoPanel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY)); add(infoPanel, c); playerListPanel = new PlayerListPanel(); c.gridx = 0; c.gridy = 1; c.weighty = 1; c.weightx = 1; c.fill = GridBagConstraints.BOTH; playerListScrollPane = new BottomScrollPane(playerListPanel); add(playerListScrollPane, c); } @Override public void setGameSettings(GameSettings settings) { gameSettings = settings; initialMeldLabel.setText("" + settings.getInitialMeldThreshold()); setNumberLabel.setText("" + settings.getStoneSetNumber()); highestValueLabel.setText("1 - " + settings.getHighestValue()); handStonesLabel.setText("" + settings.getNumberOfStonesDealt()); jokerLabel.setText("" + settings.getJokerNumber()); colorLabel.setText("" + settings.getStoneColors().size()); noLimitsLabel.setVisible(settings.isNoLimits()); } @Override public void setHeapCapacity(int capacity) { heapBar.setMaximum(capacity); } @Override public void setHeapSize(int size) { heapBar.setValue(size); if (size > 0) { heapBar.setString("" + size); } else { heapBar.setIndeterminate(true); heapBar.setString("leer"); } } private JPanel createGameInfoPanel() { JPanel panel = new JPanel(); panel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.WEST; panel.add(new JLabel("Stapel: "), c); c.gridx = 1; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; heapBar = new JProgressBar(); heapBar.setPreferredSize(new Dimension(16, 16)); panel.add(heapBar, c); heapBar.setStringPainted(true); return panel; } private JPanel createRuleInfoPanel() { JPanel panel = new JPanel(); panel.setLayout(new GridBagLayout()); initialMeldLabel = createRuleLine(panel, "Auslegeschranke", 0); setNumberLabel = createRuleLine(panel, "Steins\u00e4tze", 1); highestValueLabel = createRuleLine(panel, "Steinwert", 2); handStonesLabel = createRuleLine(panel, "Startsteine", 3); jokerLabel = createRuleLine(panel, "Joker", 4); colorLabel = createRuleLine(panel, "Farben", 5); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 6; c.gridwidth = 2; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.CENTER; noLimitsLabel = new JLabel("No Limits"); noLimitsLabel.setHorizontalAlignment(SwingConstants.CENTER); panel.add(noLimitsLabel, c); return panel; } private JLabel createRuleLine(JPanel panel, String name, int line) { GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = line; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; JLabel nameLabel = new JLabel(name + ": "); nameLabel.setPreferredSize(new Dimension(0,nameLabel.getPreferredSize().height)); panel.add(nameLabel, c); JLabel label = new JLabel(""); label.setHorizontalAlignment(SwingConstants.RIGHT); c.weightx = 0; c.gridx = 1; c.anchor = GridBagConstraints.EAST; panel.add(label, c); return label; } @SuppressWarnings("serial") class BottomScrollPane extends JPanel { JComponent content; JViewport viewport; JScrollBar scrollBar; boolean scrollToBottom; public BottomScrollPane(JComponent content) { setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; viewport = new JViewport(); add(viewport, c); this.content = content; viewport.setView(content); scrollBar = new JScrollBar(JScrollBar.VERTICAL); scrollBar.setBorder(new LineBorder(Color.BLACK, 0)); c.weightx = 0; add(scrollBar, c); ComponentAdapter resizeListener = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { onResize(); } }; addComponentListener(resizeListener); content.addComponentListener(resizeListener); scrollBar.addAdjustmentListener(new AdjustmentListener() { @Override public void adjustmentValueChanged(AdjustmentEvent arg0) { scrollViewport(); } }); scrollToBottom(); } public void scrollToBottom() { scrollToBottom = true; } private void onResize() { int oldValue = 0; if (!scrollToBottom) { oldValue = scrollBar.getMaximum() - scrollBar.getVisibleAmount() - scrollBar.getValue(); } scrollToBottom = false; int max = content.getHeight(); int extent = viewport.getHeight(); int value = Math.max(0, max - extent - oldValue); scrollBar.setVisible(extent != max); scrollBar.setValues(value, extent, 0, max); scrollViewport(); } private void scrollViewport() { viewport.setViewPosition(new Point(0, scrollBar.getValue())); } } static class InfoPanel extends JPanel { JPanel ruleInfoPanel; JPanel gameInfoPanel; JCheckBox showRules; JProgressBar heapBar; public InfoPanel(JPanel gameInfo, JPanel ruleInfo) { ruleInfoPanel = ruleInfo; gameInfoPanel = gameInfo; setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.insets = new Insets(4, 8, 4, 8); add(gameInfoPanel, c); showRules = new JCheckBox("Regeln"); showRules.setSelected(true); setupTriangleIcons(showRules); c.insets = new Insets(0, 4, 0, 4); add(showRules, c); showRules.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg) { boolean selected = showRules.isSelected(); ruleInfoPanel.setVisible(selected); showRules.setPressedIcon(selected ? showRules.getIcon() : showRules.getSelectedIcon()); } }); c.insets = new Insets(4, 8, 4, 8); add(ruleInfoPanel, c); } private void setupTriangleIcons(JCheckBox test) { BufferedImage img1 = new BufferedImage(8, 8, BufferedImage.TYPE_3BYTE_BGR); BufferedImage img2 = new BufferedImage(8, 8, BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = img1.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(getBackground()); g.fillRect(0, 0, 8, 8); g.setColor(Color.BLACK); Polygon p = new Polygon(); p.addPoint(0, 0); p.addPoint(8, 4); p.addPoint(0, 8); g.fillPolygon(p); g = img2.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(getBackground()); g.fillRect(0, 0, 8, 8); g.setColor(Color.BLACK); p = new Polygon(); p.addPoint(0, 0); p.addPoint(4, 8); p.addPoint(8, 0); g.fillPolygon(p); test.setIcon(new ImageIcon(img1)); test.setSelectedIcon(new ImageIcon(img2)); test.setPressedIcon(new ImageIcon(img1)); test.setRolloverEnabled(false); test.setFocusPainted(false); } } class PlayerListItem extends JPanel { JLabel playerName; JLabel playerStatus; JLabel playerColor; public PlayerListItem(IPlayer player) { setLayout(new GridBagLayout()); setBorder(new EmptyBorder(0, 4, 0, 4)); PlayerSettings settings = player.getPlayerSettings(); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.gridheight = gameSettings.doSeeHandSize() ? 3 : 2; c.weighty = 1; c.insets = new Insets(4, 4, 4, 4); playerColor = new JLabel(ImageUtil.createColorIcon( settings.getColor(), 12, 1)); add(playerColor, c); c.gridx = 1; c.gridy = 0; c.gridheight = 1; c.gridwidth = 2; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; c.insets = new Insets(2, 2, 2, 2); playerName = new JLabel(settings.getName()); playerName.putClientProperty("html.disable", Boolean.TRUE); add(playerName, c); c.gridx = 1; c.gridy = 1; String status = "Stein gezogen"; if (player.wasLastTurnInvalid()) { status = "ungültiger Zug"; if (!player.getLaidOut()) { status = "ungültig, nicht rausgekommen"; } } else { if (!player.getLaidOut()) { status = "nicht rausgekommen"; } else if (player.getLastTurnStoneCount() == 1) { status = "1 Stein abgelegt"; } else if (player.getLastTurnStoneCount() > 1) { status = player.getLastTurnStoneCount() + " Steine abgelegt"; } } playerStatus = new JLabel(status); add(playerStatus, c); if (gameSettings.doSeeHandSize()) { JLabel handSizeLabel = new JLabel("Handsteine: "); JLabel handSizeInfo = new JLabel("" + player.getHand().getSize()); c.gridy = 2; c.gridwidth = 1; add(handSizeLabel, c); c.gridx = 2; c.weightx = 0; c.insets = new Insets(2, 4, 2, 4); c.anchor = GridBagConstraints.EAST; add(handSizeInfo, c); } } } class PlayerListPanel extends JPanel { JPanel startSpacer; List listItems = new ArrayList(); public PlayerListPanel() { setBackground(Color.GRAY); setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); startSpacer = new JPanel(); startSpacer.setBackground(Color.GRAY); startSpacer.setPreferredSize(new Dimension(0, 0)); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; add(startSpacer, c); } public void setPlayers(List players) { for (PlayerListItem item : listItems) { remove(item); } listItems.clear(); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; for (IPlayer player : players) { c.gridy++; c.insets = new Insets(c.gridy == 1 ? 0 : 1, 0, 0, 0); PlayerListItem item = new PlayerListItem(player); listItems.add(item); add(item, c); } } @Override public Dimension getPreferredSize() { Dimension oldPref = super.getPreferredSize(); return new Dimension(0, oldPref.height); } } @Override public void setPlayers(List players) { playerListPanel.setPlayers(players); } }