package mage.client.components.ability; import mage.client.SessionHandler; import mage.client.util.ImageHelper; import mage.client.util.SettingsManager; import mage.client.util.gui.GuiDisplayUtil; import mage.remote.Session; import mage.view.AbilityPickerView; import org.apache.log4j.Logger; import org.jdesktop.layout.GroupLayout; import org.jdesktop.layout.LayoutStyle; import org.jdesktop.swingx.JXPanel; import org.jsoup.Jsoup; import org.mage.card.arcane.ManaSymbols; import org.mage.card.arcane.UI; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; /** * Dialog for choosing abilities. * * @author nantuko */ public class AbilityPicker extends JXPanel implements MouseWheelListener { private static final String DEFAULT_MESSAGE = "Choose spell or ability to play (single-click)"; private static final int DIALOG_WIDTH = 440; private static final int DIALOG_HEIGHT = 260; private static final Logger log = Logger.getLogger(AbilityPicker.class); private JList rows; private List<Object> choices; private String message = DEFAULT_MESSAGE; private Session session; private UUID gameId; private BackgroundPainter mwPanelPainter; private JScrollPane jScrollPane2; private JTextField title; private Image rightImage; private Image rightImageHovered; private static final String IMAGE_RIGHT_PATH = "/game/right.png"; private static final String IMAGE_RIGHT_HOVERED_PATH = "/game/right_hovered.png"; private static final Color SELECTED_COLOR = new Color(64, 147, 208); private static Color BORDER_COLOR = new Color(0, 0, 0, 50); private boolean selected = false; public AbilityPicker() { setSize(DIALOG_WIDTH, DIALOG_HEIGHT); initComponents(); jScrollPane2.setOpaque(false); jScrollPane2.getViewport().setOpaque(false); UIManager.put("ScrollBar.width", 17); jScrollPane2.getHorizontalScrollBar().setUI(new MageScrollbarUI()); jScrollPane2.getVerticalScrollBar().setUI(new MageScrollbarUI()); } public AbilityPicker(List<Object> choices, String message) { this.choices = choices; setSize(DIALOG_WIDTH, DIALOG_HEIGHT); if (message != null) { this.message = message + " (single-click)"; } initComponents(); jScrollPane2.setOpaque(false); jScrollPane2.getViewport().setOpaque(false); UIManager.put("ScrollBar.width", 17); jScrollPane2.getHorizontalScrollBar().setUI(new MageScrollbarUI()); jScrollPane2.getVerticalScrollBar().setUI(new MageScrollbarUI()); } public void init(UUID gameId) { this.gameId = gameId; } public void cleanUp() { for (MouseListener ml : this.getMouseListeners()) { this.removeMouseListener(ml); } } public void show(AbilityPickerView choices, Point p) { this.choices = new ArrayList<>(); this.selected = true; // to stop previous modal for (Map.Entry<UUID, String> choice : choices.getChoices().entrySet()) { this.choices.add(new AbilityPickerAction(choice.getKey(), choice.getValue())); } this.choices.add(new AbilityPickerAction(null, "Cancel")); show(this.choices); } private void show(List<Object> choices) { this.choices = choices; this.selected = true; // to stop previous modal rows.setListData(this.choices.toArray()); this.rows.setSelectedIndex(0); this.selected = false; // back to false - waiting for selection setVisible(true); Point centered = SettingsManager.instance.getComponentPosition(DIALOG_WIDTH, DIALOG_HEIGHT); this.setLocation(centered.x, centered.y); GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); //startModal(); } private void initComponents() { JLabel jLabel1; JLabel jLabel3; Color textColor = Color.white; mwPanelPainter = new BackgroundPainter(); jLabel1 = new JLabel(); jLabel3 = new JLabel(); title = new JTextField(); jScrollPane2 = new JScrollPane(); setBackground(textColor); setBackgroundPainter(mwPanelPainter); jLabel1.setFont(new Font("Times New Roman", 1, 18)); jLabel1.setForeground(textColor); jLabel1.setText(message); jLabel3.setForeground(textColor); jLabel3.setHorizontalAlignment(SwingConstants.TRAILING); jLabel3.setText("Selected:"); title.setFont(new Font("Tahoma", 1, 11)); title.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); jScrollPane2.setBorder(null); jScrollPane2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); jScrollPane2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); rightImage = ImageHelper.loadImage(IMAGE_RIGHT_PATH); rightImageHovered = ImageHelper.loadImage(IMAGE_RIGHT_HOVERED_PATH); setOpaque(false); rows = new JList(); rows.setBackground(textColor); rows.setCellRenderer(new ImageRenderer()); rows.ensureIndexIsVisible(rows.getModel().getSize()); rows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); rows.setLayoutOrientation(JList.VERTICAL); rows.setMaximumSize(new Dimension(32767, 32767)); rows.setMinimumSize(new Dimension(67, 16)); rows.setOpaque(false); rows.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) { objectMouseClicked(evt); } } }); rows.setSelectedIndex(0); rows.setFont(new Font("Times New Roman", 1, 17)); rows.setBorder(BorderFactory.createEmptyBorder()); rows.addMouseWheelListener(this); jScrollPane2.setViewportView(rows); jScrollPane2.setViewportBorder(BorderFactory.createEmptyBorder()); GroupLayout layout = new GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( GroupLayout.TRAILING, layout.createSequentialGroup().addContainerGap().add( layout.createParallelGroup(GroupLayout.TRAILING).add(GroupLayout.LEADING, jScrollPane2, GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE).add(GroupLayout.LEADING, layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( GroupLayout.LEADING, layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) ) .addPreferredGap(LayoutStyle.RELATED) .add( layout.createParallelGroup(GroupLayout.TRAILING) .add( GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( layout.createSequentialGroup().add( layout.createParallelGroup(GroupLayout.LEADING).add( layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) .add(5, 5, 5) .add( layout.createParallelGroup(GroupLayout.BASELINE) ) ).add(layout.createSequentialGroup().add(8, 8, 8))) .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); } @Override public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); int index = rows.getSelectedIndex(); if (notches < 0) { if (index > 0) { rows.setSelectedIndex(index - 1); rows.repaint(); } } else if (index < choices.size() - 1) { rows.setSelectedIndex(index + 1); rows.repaint(); } } private void objectMouseClicked(MouseEvent event) { int index = rows.getSelectedIndex(); AbilityPickerAction action = (AbilityPickerAction) choices.get(index); action.actionPerformed(null); } public static class ImageRenderer2 extends JEditorPane implements ListCellRenderer { public final Map<String, String> cache = new HashMap<>(); @Override public Component getListCellRendererComponent( javax.swing.JList list, Object value, int index, boolean isSelected, boolean cellHasFocus ) { setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 6)); UI.setHTMLEditorKit(this); setOpaque(false); setBackground(new Color(0, 0, 0, 0)); String text = value.toString(); if (cache.containsKey(text)) { text = cache.get(text); } else { StringBuilder buffer = getHtmlForText(isSelected, text); String rendered = buffer.toString(); cache.put(text, rendered); text = rendered; } final String finalText = text; // System.out.println(finalText); ImageRenderer2.super.setText(finalText); setCaretPosition(0); return this; } private StringBuilder getHtmlForText(boolean isSelected, String text) { int fontSize = 16; String fontFamily = "arial"; final StringBuilder buffer = new StringBuilder(512); buffer.append("<html><body style='font-family:"); buffer.append(fontFamily); buffer.append(";font-size:"); buffer.append(fontSize); buffer.append("pt;margin:3px 3px 3px 3px;"); if (isSelected) { buffer.append("color: #4093D0'>"); } else { buffer.append("color: #FFFFFF'>"); } buffer.append("<b>"); text = text.replaceAll("#([^#]+)#", "<i>$1</i>"); text = text.replaceAll("\\s*//\\s*", "<hr width='50%'>"); text = text.replace("\r\n", "<div style='font-size:5pt'></div>"); //text += "<br>"; if (!text.isEmpty()) { buffer.append(ManaSymbols.replaceSymbolsWithHTML(text, ManaSymbols.Type.DIALOG)); } buffer.append("</b></body></html>"); return buffer; } } class ImageRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); JLabel label = ((JLabel) c); label.setOpaque(false); label.setForeground(Color.white); if (choices.size() <= index) { return label; } Object object = choices.get(index); String name = object.toString(); label.setText(name); if (isSelected) { label.setIcon(new ImageIcon(rightImageHovered)); label.setForeground(SELECTED_COLOR); //label.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); label.setBorder(BorderFactory.createEmptyBorder()); } else { label.setIcon(new ImageIcon(rightImage)); } return label; } private static final long serialVersionUID = 7689696087189956997L; } private synchronized void startModal() { try { if (SwingUtilities.isEventDispatchThread()) { EventQueue theQueue = getToolkit().getSystemEventQueue(); while (!selected) { AWTEvent event = theQueue.getNextEvent(); Object source = event.getSource(); boolean dispatch = true; /*if (event instanceof MouseEvent) { MouseEvent e = (MouseEvent) event; if (e.getID() == MouseEvent.MOUSE_PRESSED || e.getID() == MouseEvent.MOUSE_CLICKED) { MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this); if (!this.contains(m.getPoint())) { selected = true; cancel(); setVisible(false); dispatch = false; } } }*/ if (event instanceof MouseEvent) { MouseEvent e = (MouseEvent) event; MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this); if (!this.contains(m.getPoint()) && e.getID() != MouseEvent.MOUSE_DRAGGED) { dispatch = false; } } if (dispatch) { if (event instanceof ActiveEvent) { ((ActiveEvent) event).dispatch(); } else if (source instanceof Component) { ((Component) source).dispatchEvent(event); } else if (source instanceof MenuComponent) { ((MenuComponent) source).dispatchEvent(event); } } } } else { while (!selected) { wait(); } } } catch (InterruptedException ignored) { } } public static void main(String[] argv) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception ex) { } JFrame jframe = new JFrame("Test"); List<Object> objectList = new ArrayList<>(); objectList.add("T: add {R} to your mana pool. 111111111111111111111111111"); objectList.add("T: add {B} to your mana pool. {source} deals 1 damage to you."); objectList.add("{T}: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("T: add {B} to your mana pool"); objectList.add("Cancel"); AbilityPicker panel = new AbilityPicker(objectList, "Choose ability"); jframe.add(panel); panel.show(objectList); jframe.setSize(DIALOG_WIDTH, DIALOG_HEIGHT); jframe.setVisible(true); } public class AbilityPickerAction extends AbstractAction { private final UUID id; public AbilityPickerAction(UUID id, String choice) { this.id = id; putValue(Action.NAME, capitalizeFirstLetter(choice)); } private String capitalizeFirstLetter(String choice) { if (choice == null || choice.isEmpty()) { return choice; } choice = Jsoup.parse(choice).text(); // decode HTML entities and strip tags return choice.substring(0, 1).toUpperCase() + choice.substring(1); } @Override public void actionPerformed(ActionEvent e) { // cancel if (id == null) { cancel(); } else { SessionHandler.sendPlayerUUID(gameId, id); } setVisible(false); AbilityPicker.this.selected = true; } @Override public String toString() { return (String) getValue(Action.NAME); } } private void cancel() { try { SessionHandler.sendPlayerBoolean(gameId, false); } catch (Exception e) { log.error("Couldn't cancel choose dialog: " + e, e); } } }