package mage.client.cards; import mage.cards.MageCard; import mage.client.MagePane; import mage.client.plugins.impl.Plugins; import mage.view.CardView; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; /** * Created by StravantUser on 2016-09-22. */ public class CardDraggerGlassPane implements MouseListener, MouseMotionListener { private final DragCardSource source; private Component dragComponent; private JRootPane currentRoot; private JComponent glassPane; private ArrayList<CardView> currentCards; private MageCard dragView; private DragCardTarget currentDragTarget; private boolean isDragging; // This should not be strictly needed, but for some reason I can't figure out getDeepestComponentAt and // getComponentAt do not seem to work correctly for our setup if called on the root MageFrame. private MagePane currentEventRootMagePane; public CardDraggerGlassPane(DragCardSource source) { this.source = source; } public void beginDrag(Component c, MouseEvent e) { // Start drag if (isDragging) { return; } isDragging = true; // Record what we are dragging on dragComponent = c; currentRoot = SwingUtilities.getRootPane(c); // Pane glassPane = (JComponent)currentRoot.getGlassPane(); glassPane.setLayout(null); glassPane.setOpaque(false); glassPane.setVisible(true); // Get root mage pane to handle drag targeting in Component rootMagePane = c; while (rootMagePane != null && !(rootMagePane instanceof MagePane)) { rootMagePane = rootMagePane.getParent(); } if (rootMagePane == null) { throw new RuntimeException("CardDraggerGlassPane::beginDrag not in a MagePane?"); } else { currentEventRootMagePane = (MagePane)rootMagePane; } // Hook up events c.addMouseListener(this); c.addMouseMotionListener(this); // Event to local space e = SwingUtilities.convertMouseEvent(c, e, glassPane); // Get the cards to drag currentCards = new ArrayList<>(source.dragCardList()); // Make a view for the first one and add it to us dragView = Plugins.instance.getMageCard(currentCards.get(0), null, new Dimension(100, 140), null, true, false); for (MouseListener l: dragView.getMouseListeners()) { dragView.removeMouseListener(l); } for (MouseMotionListener l : dragView.getMouseMotionListeners()) { dragView.removeMouseMotionListener(l); } dragView.setLocation(e.getX(), e.getY()); glassPane.add(dragView); // Notify the sounce source.dragCardBegin(); // Update the target currentDragTarget = null; updateCurrentTarget(SwingUtilities.convertMouseEvent(glassPane, e, currentEventRootMagePane), false); } // e is relative to currentRoot private void updateCurrentTarget(MouseEvent e, boolean isEnding) { Component mouseOver = SwingUtilities.getDeepestComponentAt(currentEventRootMagePane, e.getX(), e.getY()); while (mouseOver != null) { if (mouseOver instanceof DragCardTarget) { DragCardTarget target = (DragCardTarget)mouseOver; MouseEvent targetEvent = SwingUtilities.convertMouseEvent(currentEventRootMagePane, e, mouseOver); if (target != currentDragTarget) { if (currentDragTarget != null) { MouseEvent oldTargetEvent = SwingUtilities.convertMouseEvent(currentEventRootMagePane, e, (Component) currentDragTarget); currentDragTarget.dragCardExit(oldTargetEvent); } currentDragTarget = target; currentDragTarget.dragCardEnter(targetEvent); } if (isEnding) { currentDragTarget.dragCardExit(targetEvent); currentDragTarget.dragCardDrop(targetEvent, source, currentCards); } else { currentDragTarget.dragCardMove(targetEvent); } return; } mouseOver = mouseOver.getParent(); } if (currentDragTarget != null) { MouseEvent oldTargetEvent = SwingUtilities.convertMouseEvent(currentEventRootMagePane, e, (Component)currentDragTarget); currentDragTarget.dragCardExit(oldTargetEvent); } currentDragTarget = null; } public boolean isDragging() { return isDragging; } /** * Mouse released -> we are done the drag */ @Override public void mouseReleased(MouseEvent e) { // No longer dragging isDragging = false; // Remove listeners dragComponent.removeMouseListener(this); dragComponent.removeMouseMotionListener(this); // Convert the event into root coords e = SwingUtilities.convertMouseEvent(dragComponent, e, currentEventRootMagePane); // Remove the drag card glassPane.remove(dragView); glassPane.repaint(); // Let the drag source know source.dragCardEnd(currentDragTarget); // Update the target, and do the drop updateCurrentTarget(e, true); } @Override public void mouseDragged(MouseEvent e) { // Update the view MouseEvent glassE = SwingUtilities.convertMouseEvent(dragComponent, e, glassPane); dragView.setLocation(glassE.getX(), glassE.getY()); dragView.repaint(); // Convert the event into root coords and update target e = SwingUtilities.convertMouseEvent(dragComponent, e, currentEventRootMagePane); updateCurrentTarget(e, false); } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) {} }