package mage.client.util.gui; import javax.swing.*; import java.awt.*; import java.util.*; import java.util.List; /** * Class for dealing with arrows in the game. * * @author nantuko, noxx */ public class ArrowBuilder { private static ArrowBuilder instance; static { instance = new ArrowBuilder(); } public static ArrowBuilder getBuilder() { return instance; } /** * The top panel where arrow panels are added to. */ private JPanel arrowsManagerPanel; /** * Stores arrow panels per game */ private final Map<UUID, JPanel> arrowPanels = new HashMap<>(); private final Map<UUID, Map<Type, List<Arrow>>> map = new HashMap<>(); private int currentWidth; private int currentHeight; public enum Type { PAIRED, SOURCE, TARGET, COMBAT, ENCHANT_PLAYERS } /** * Get the panel where all arrows are being drawn. * @return */ public JPanel getArrowsManagerPanel() { if (arrowsManagerPanel == null) { synchronized (ArrowBuilder.class) { if (arrowsManagerPanel == null) { arrowsManagerPanel = new JPanel(); arrowsManagerPanel.setVisible(true); arrowsManagerPanel.setOpaque(false); arrowsManagerPanel.setLayout(null); } } } return arrowsManagerPanel; } private JPanel getArrowsPanel(UUID gameId) { if (!arrowPanels.containsKey(gameId)) { JPanel arrowPanel = new JPanel(); arrowPanel.setVisible(true); arrowPanel.setOpaque(false); arrowPanel.setLayout(null); arrowPanel.setSize(currentWidth, currentHeight); arrowPanels.put(gameId, arrowPanel); getArrowsManagerPanel().add(arrowPanel); return arrowPanel; } return arrowPanels.get(gameId); } /** * Not synchronized method for arrows panel. * Doesn't create JPanel in case the panel doesn't exist. * Works faster. * * @return */ /*public JPanel getPanelRef() { return arrowsManagerPanel; }*/ /** * Adds new arrow. * * @param startX * @param startY * @param endX * @param endY * @param color */ public void addArrow(UUID gameId, int startX, int startY, int endX, int endY, Color color, Type type) { JPanel p = getArrowsPanel(gameId); Arrow arrow = new Arrow(); arrow.setColor(color); arrow.setArrowLocation(startX, startY, endX, endY); arrow.setBounds(0, 0, Math.max(startX, endX) + 40, Math.max(startY, endY) + 30); // 30 is offset for arrow heads (being cut otherwise) synchronized (map) { p.add(arrow); Map<Type, java.util.List<Arrow>> innerMap = map.computeIfAbsent(gameId, k -> new HashMap<>()); java.util.List<Arrow> arrows = innerMap.computeIfAbsent(type, k -> new ArrayList<>()); arrows.add(arrow); } p.revalidate(); p.repaint(); } /** * Removes all arrows from the screen. */ public void removeAllArrows(UUID gameId) { if (map.containsKey(gameId)) { Map<Type, List<Arrow>> innerMap = map.get(gameId); JPanel p = getArrowsPanel(gameId); synchronized (map) { if (p != null && p.getComponentCount() > 0) { p.removeAll(); p.revalidate(); p.repaint(); } innerMap.clear(); map.remove(gameId); } } } public void removeArrowsByType(UUID gameId, Type type) { if (map.containsKey(gameId)) { Map<Type, List<Arrow>> innerMap = map.get(gameId); java.util.List<Arrow> arrows = innerMap.get(type); if (arrows != null && !arrows.isEmpty()) { JPanel p = getArrowsPanel(gameId); synchronized (map) { for (Arrow arrow : arrows) { p.remove(arrow); } innerMap.put(type, new ArrayList<>()); } p.revalidate(); p.repaint(); } } } public void setSize(int width, int height) { this.currentWidth = width; this.currentHeight = height; if (arrowsManagerPanel != null) { arrowsManagerPanel.setSize(width, height); } for (JPanel arrowPanel : arrowPanels.values()) { arrowPanel.setSize(width, height); arrowPanel.repaint(); } } public void hideAllPanels() { for (JPanel arrowPanel : arrowPanels.values()) { arrowPanel.setVisible(false); } } public void showPanel(UUID gameId) { if (arrowPanels.containsKey(gameId)) { arrowPanels.get(gameId).setVisible(true); } } }