/* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ package mage.client.game; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.UUID; import javax.swing.JButton; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.UIManager; import mage.client.SessionHandler; import mage.client.components.MageTextArea; import mage.client.constants.Constants; import mage.client.game.FeedbackPanel.FeedbackMode; import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION; import mage.client.util.GUISizeHelper; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_YES; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_NO; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_YES; /** * Panel with buttons that copy the state of feedback panel. * * @author ayrat, JayDi85 */ public class HelperPanel extends JPanel { private javax.swing.JButton btnLeft; private javax.swing.JButton btnRight; private javax.swing.JButton btnSpecial; private javax.swing.JButton btnUndo; //private javax.swing.JButton btnEndTurn; //private javax.swing.JButton btnStopTimer; private JScrollPane textAreaScrollPane; private MageTextArea dialogTextArea; JPanel buttonGrid; JPanel buttonContainer; private javax.swing.JButton linkLeft; private javax.swing.JButton linkRight; private javax.swing.JButton linkSpecial; private javax.swing.JButton linkUndo; private final Object tooltipBackground = UIManager.get("info"); private static final String CMD_AUTO_ANSWER_ID_YES = "cmdAutoAnswerIdYes"; private static final String CMD_AUTO_ANSWER_ID_NO = "cmdAutoAnswerIdNo"; private static final String CMD_AUTO_ANSWER_NAME_YES = "cmdAutoAnswerNameYes"; private static final String CMD_AUTO_ANSWER_NAME_NO = "cmdAutoAnswerNameNo"; private static final String CMD_AUTO_ANSWER_RESET_ALL = "cmdAutoAnswerResetAll"; // popup menu for set automatic answers private JPopupMenu popupMenuAskYes; private JPopupMenu popupMenuAskNo; // originalId of feedback causing ability private UUID originalId; private String message; private UUID gameId; private boolean gameNeedFeedback = false; public HelperPanel() { initComponents(); } public void init(UUID gameId) { this.gameId = gameId; } public void changeGUISize() { setGUISize(); } private void setGUISize() { //this.setMaximumSize(new Dimension(getParent().getWidth(), Integer.MAX_VALUE)); textAreaScrollPane.setMaximumSize(new Dimension(getParent().getWidth(), GUISizeHelper.gameDialogAreaTextHeight)); textAreaScrollPane.setPreferredSize(new Dimension(getParent().getWidth(), GUISizeHelper.gameDialogAreaTextHeight)); // dialogTextArea.setMaximumSize(new Dimension(getParent().getWidth(), Integer.MAX_VALUE)); // dialogTextArea.setPreferredSize(new Dimension(getParent().getWidth(), GUISizeHelper.gameDialogAreaTextHeight)); // buttonContainer.setPreferredSize(new Dimension(getParent().getWidth(), GUISizeHelper.gameDialogButtonHeight + 4)); // buttonContainer.setMinimumSize(new Dimension(160, GUISizeHelper.gameDialogButtonHeight + 20)); // buttonContainer.setMaximumSize(new Dimension(Integer.MAX_VALUE, GUISizeHelper.gameDialogButtonHeight + 4)); btnLeft.setFont(GUISizeHelper.gameDialogAreaFont); btnRight.setFont(GUISizeHelper.gameDialogAreaFont); btnSpecial.setFont(GUISizeHelper.gameDialogAreaFont); btnUndo.setFont(GUISizeHelper.gameDialogAreaFont); if (message != null) { int pos = this.message.indexOf("font-size:"); if (pos > 0) { String newMessage = this.message.substring(0, pos + 10) + GUISizeHelper.gameDialogAreaFontSizeBig + this.message.substring(pos + 12); pos = this.message.indexOf("font-size:", pos + 10); if (pos > 0) { newMessage = this.message.substring(0, pos + 10) + GUISizeHelper.gameDialogAreaFontSizeSmall + this.message.substring(pos + 12); } setBasicMessage(newMessage); } } autoSizeButtonsAndFeedbackState(); GUISizeHelper.changePopupMenuFont(popupMenuAskNo); GUISizeHelper.changePopupMenuFont(popupMenuAskYes); revalidate(); repaint(); } private void initComponents() { initPopupMenuTriggerOrder(); setBackground(new Color(0, 0, 0, 100)); setLayout(new GridLayout(0, 1)); setOpaque(false); dialogTextArea = new MageTextArea(); dialogTextArea.setText(""); dialogTextArea.setOpaque(false); textAreaScrollPane = new JScrollPane(dialogTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); textAreaScrollPane.setOpaque(false); textAreaScrollPane.setBackground(new Color(0, 0, 0, 0)); textAreaScrollPane.getViewport().setOpaque(false); textAreaScrollPane.setBorder(null); textAreaScrollPane.setViewportBorder(null); add(textAreaScrollPane); buttonContainer = new JPanel(); buttonContainer.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); buttonContainer.setOpaque(false); add(buttonContainer); buttonGrid = new JPanel(); // buttons layout auto changes by autoSizeButtonsAndFeedbackState buttonGrid.setOpaque(false); buttonContainer.add(buttonGrid); btnSpecial = new JButton("Special"); btnSpecial.setVisible(false); buttonGrid.add(btnSpecial); btnLeft = new JButton("OK"); btnLeft.setVisible(false); buttonGrid.add(btnLeft); btnRight = new JButton("Cancel"); btnRight.setVisible(false); buttonGrid.add(btnRight); btnUndo = new JButton("Undo"); btnUndo.setVisible(false); buttonGrid.add(btnUndo); MouseListener checkPopupAdapter = new MouseAdapter() { @Override public void mousePressed(MouseEvent me) { checkPopupMenu(me); } @Override public void mouseReleased(MouseEvent me) { checkPopupMenu(me); } }; btnLeft.addMouseListener(checkPopupAdapter); btnLeft.addActionListener(evt -> { if (linkLeft != null) { clickButton(linkLeft); } }); btnRight.addMouseListener(checkPopupAdapter); btnRight.addActionListener(evt -> { if (linkRight != null) { clickButton(linkRight); } }); btnSpecial.addActionListener(evt -> { if (linkSpecial != null) { clickButton(linkSpecial); } }); btnUndo.addActionListener(evt -> { if (linkUndo != null) { { Thread worker = new Thread(() -> SwingUtilities.invokeLater(() -> linkUndo.doClick())); worker.start(); } } }); // sets a darker background and higher simiss time fur tooltip in the feedback / helper panel dialogTextArea.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent me) { ToolTipManager.sharedInstance().setDismissDelay(100 * 1000); UIManager.put("info", Color.DARK_GRAY); } @Override public void mouseExited(MouseEvent me) { ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS); UIManager.put("info", tooltipBackground); } }); } private void checkPopupMenu(MouseEvent me) { if (me.isPopupTrigger() && originalId != null) { // only Yes/No requests from abilities can be automated JButton source = (JButton) me.getSource(); if (source.getActionCommand().startsWith(QUESTION.toString())) { showPopupMenu(me.getComponent(), source.getActionCommand()); me.consume(); } } } private void clickButton(final JButton button) { Thread worker = new Thread(() -> SwingUtilities.invokeLater(() -> { setState("", false, "", false, null); setSpecial("", false); button.doClick(); })); worker.start(); } public void setState(String txtLeft, boolean leftVisible, String txtRight, boolean rightVisible, FeedbackMode mode) { this.btnLeft.setVisible(leftVisible); if (!txtLeft.isEmpty()) { this.btnLeft.setText(txtLeft); if (mode != null) { this.btnLeft.setActionCommand(mode.toString() + txtLeft); } } this.btnRight.setVisible(rightVisible); if (!txtRight.isEmpty()) { this.btnRight.setText(txtRight); if (mode != null) { this.btnRight.setActionCommand(mode.toString() + txtRight); } } autoSizeButtonsAndFeedbackState(); } public void setSpecial(String txtSpecial, boolean specialVisible) { this.btnSpecial.setVisible(specialVisible); this.btnSpecial.setText(txtSpecial); } public void setUndoEnabled(boolean enabled) { this.btnUndo.setVisible(enabled); autoSizeButtonsAndFeedbackState(); } public void setLeft(String text, boolean visible) { this.btnLeft.setVisible(visible); if (!text.isEmpty()) { this.btnLeft.setText(text); } autoSizeButtonsAndFeedbackState(); } public void setRight(String txtRight, boolean rightVisible) { this.btnRight.setVisible(rightVisible); if (!txtRight.isEmpty()) { this.btnRight.setText(txtRight); } autoSizeButtonsAndFeedbackState(); } public void setGameNeedFeedback(boolean need) { this.gameNeedFeedback = need; } public void autoSizeButtonsAndFeedbackState() { // two mode: same size for small texts (flow), different size for long texts (grid) // plus colorize feedback panel on player's priority int BUTTONS_H_GAP = 15; Color ACTIVE_FEEDBACK_BACKGROUND_COLOR = new Color(0, 255, 0, 50); // cleanup current settings to default (flow layout - different sizes) this.buttonGrid.setLayout(new FlowLayout(FlowLayout.CENTER, BUTTONS_H_GAP, 0)); this.buttonGrid.setPreferredSize(null); ArrayList buttons = new ArrayList<>(); if (this.btnLeft.isVisible()) { buttons.add(this.btnLeft); } if (this.btnRight.isVisible()) { buttons.add(this.btnRight); } if (this.btnSpecial.isVisible()) { buttons.add(this.btnSpecial); } if (this.btnUndo.isVisible()) { buttons.add(this.btnUndo); } // color panel on player's feedback waiting if (this.gameNeedFeedback) { // wait player's action this.setOpaque(true); this.setBackground(ACTIVE_FEEDBACK_BACKGROUND_COLOR); } else { // inform about other players this.setOpaque(false); } if (buttons.size() == 0) { return; } this.buttonGrid.removeAll(); for (JButton button : buttons) { this.buttonGrid.add(button); } // random text test (click to any objects to change) /* Integer i = 1 + RandomUtil.nextInt(50); String longText = i.toString() + "-"; while (longText.length() < i) {longText += "a";} this.btnRight.setText(longText); //*/ // search max preferred size to draw full button's text int needButtonSizeW = 0; for (JButton button : buttons) { needButtonSizeW = Math.max(needButtonSizeW, button.getPreferredSize().width); } // search max const size int constButtonSizeW = GUISizeHelper.gameDialogButtonWidth * 200 / 100; int constGridSizeW = buttons.size() * constButtonSizeW + BUTTONS_H_GAP * (buttons.size() - 1); int constGridSizeH = Math.round(GUISizeHelper.gameDialogButtonHeight * 150 / 100); if (needButtonSizeW < constButtonSizeW) { // same size mode (grid) GridLayout gl = new GridLayout(1, buttons.size(), BUTTONS_H_GAP, 0); this.buttonGrid.setLayout(gl); this.buttonGrid.setPreferredSize(new Dimension(constGridSizeW, constGridSizeH)); } else { // different size mode (flow) -- already used by default //FlowLayout fl = new FlowLayout(FlowLayout.CENTER, BUTTONS_H_GAP, 0); //this.buttonGrid.setLayout(fl); } } public void setLinks(JButton left, JButton right, JButton special, JButton undo) { this.linkLeft = left; this.linkRight = right; this.linkSpecial = special; this.linkUndo = undo; } public void setOriginalId(UUID originalId) { this.originalId = originalId; } public void setBasicMessage(String message) { this.message = message; this.dialogTextArea.setText(message, this.getWidth()); } public void setTextArea(String message) { this.dialogTextArea.setText(message, this.getWidth()); } @Override public void requestFocus() { this.btnRight.requestFocus(); } private void initPopupMenuTriggerOrder() { ActionListener actionListener = e -> handleAutoAnswerPopupMenuEvent(e); popupMenuAskYes = new JPopupMenu(); popupMenuAskNo = new JPopupMenu(); // String tooltipText = ""; JMenuItem menuItem; menuItem = new JMenuItem("Always Yes for the same text and ability"); menuItem.setActionCommand(CMD_AUTO_ANSWER_ID_YES); menuItem.addActionListener(actionListener); menuItem.setToolTipText("If the same question from the same ability would
be asked again, it's automatically answered with Yes."); popupMenuAskYes.add(menuItem); menuItem = new JMenuItem("Always No for the same text and ability"); menuItem.setActionCommand(CMD_AUTO_ANSWER_ID_NO); menuItem.setToolTipText("If the same question from the same ability would
be asked again, it's automatically answered with No."); menuItem.addActionListener(actionListener); popupMenuAskNo.add(menuItem); menuItem = new JMenuItem("Always Yes for the same text"); menuItem.setActionCommand(CMD_AUTO_ANSWER_NAME_YES); menuItem.setToolTipText("If the same question would be asked again (regardless from which source),
it's automatically answered with Yes."); menuItem.addActionListener(actionListener); popupMenuAskYes.add(menuItem); menuItem = new JMenuItem("Always No for the same text"); menuItem.setActionCommand(CMD_AUTO_ANSWER_NAME_NO); menuItem.setToolTipText("If the same question would be asked again (regardless from which source),
it's automatically answered with No."); menuItem.addActionListener(actionListener); popupMenuAskNo.add(menuItem); menuItem = new JMenuItem("Delete all automatic Yes/No settings"); menuItem.setActionCommand(CMD_AUTO_ANSWER_RESET_ALL); menuItem.addActionListener(actionListener); popupMenuAskYes.add(menuItem); menuItem = new JMenuItem("Delete all automatic Yes/No settings"); menuItem.setActionCommand(CMD_AUTO_ANSWER_RESET_ALL); menuItem.addActionListener(actionListener); popupMenuAskNo.add(menuItem); } public void handleAutoAnswerPopupMenuEvent(ActionEvent e) { switch (e.getActionCommand()) { case CMD_AUTO_ANSWER_ID_YES: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_ID_YES, gameId, originalId.toString() + '#' + message); clickButton(btnLeft); break; case CMD_AUTO_ANSWER_ID_NO: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_ID_NO, gameId, originalId.toString() + '#' + message); clickButton(btnRight); break; case CMD_AUTO_ANSWER_NAME_YES: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_TEXT_YES, gameId, message); clickButton(btnLeft); break; case CMD_AUTO_ANSWER_NAME_NO: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_TEXT_NO, gameId, message); clickButton(btnRight); break; case CMD_AUTO_ANSWER_RESET_ALL: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_RESET_ALL, gameId, null); break; } } private void showPopupMenu(Component callingComponent, String actionCommand) { // Get the location of the point 'on the screen' Point p = callingComponent.getLocationOnScreen(); // Show the JPopupMenu via program // Parameter desc // ---------------- // this - represents current frame // 0,0 is the co ordinate where the popup // is shown JPopupMenu menu; if (actionCommand.endsWith("Yes")) { menu = popupMenuAskYes; } else { menu = popupMenuAskNo; } menu.show(this, 0, 0); // Now set the location of the JPopupMenu // This location is relative to the screen menu.setLocation(p.x, p.y + callingComponent.getHeight()); } }