diff --git a/src/main/java/forge/gui/match/TargetingOverlay.java b/src/main/java/forge/gui/match/TargetingOverlay.java index c4ebdbd5fab..e2f9d2415e1 100644 --- a/src/main/java/forge/gui/match/TargetingOverlay.java +++ b/src/main/java/forge/gui/match/TargetingOverlay.java @@ -39,6 +39,13 @@ import forge.gui.match.nonsingleton.VField; import forge.gui.toolbox.FSkin; import forge.view.FView; import forge.view.arcane.CardPanel; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; /** * Semi-transparent overlay panel. Should be used with layered panes. @@ -54,6 +61,8 @@ public enum TargetingOverlay { private final List cardPanels = new ArrayList(); private final List arcs = new ArrayList(); + private Rectangle rectMouseOver = null; + /** * Semi-transparent overlay panel. Should be used with layered panes. */ @@ -75,15 +84,19 @@ public enum TargetingOverlay { cardPanels.clear(); List fields = VMatchUI.SINGLETON_INSTANCE.getFieldViews(); + rectMouseOver = null; switch (CDock.SINGLETON_INSTANCE.getArcState()) { case 0: return; case 1: // Draw only hovered card + for (CField f : CMatchUI.SINGLETON_INSTANCE.getFieldControls()) { + cardPanels.addAll(f.getView().getTabletop().getCardPanels()); + } for (VField f : fields) { if (f.getTabletop().getCardFromMouseOverPanel() != null) { - cardPanels.add(f.getTabletop().getMouseOverPanel()); + rectMouseOver = f.getTabletop().getMouseOverPanel().getVisibleRect(); break; } } @@ -102,8 +115,8 @@ public enum TargetingOverlay { for (CardPanel c : cardPanels) { if (!c.isShowing()) { continue; } endpoints.put(c.getCard().getUniqueNumber(), new Point( - (int) (c.getParent().getLocationOnScreen().getX() + c.getCardLocation().getX() - docOffsets.getX() + c.getWidth() / 4), - (int) (c.getParent().getLocationOnScreen().getY() + c.getCardLocation().getY() - docOffsets.getY() + c.getHeight() / 4) + (int) (c.getParent().getLocationOnScreen().getX() + c.getCardLocation().getX() /* - docOffsets.getX() */ + c.getWidth() / 4), + (int) (c.getParent().getLocationOnScreen().getY() + c.getCardLocation().getY() /* - docOffsets.getY() */ + c.getHeight() / 4) )); } @@ -116,6 +129,9 @@ public enum TargetingOverlay { // Enchantments Card enchanting = c.getCard().getEnchantingCard(); if (enchanting != null) { + if (enchanting.getController().equals(c.getCard().getController())) { + continue; + } arcs.add(new Point[] { endpoints.get(enchanting.getUniqueNumber()), endpoints.get(c.getCard().getUniqueNumber()) @@ -147,6 +163,71 @@ public enum TargetingOverlay { * @param g *   Graphics object */ + + // Arrow drawing code by the MAGE team, used with permission. + private Area getArrow (float length, float bendPercent) { + float p1x = 0, p1y = 0; + float p2x = length, p2y = 0; + float cx = length / 2, cy = length / 8f * bendPercent; + + int bodyWidth = 10; + float headSize = 17; + + float adjSize, ex, ey, abs_e; + adjSize = (float)(bodyWidth / 2 / Math.sqrt(2)); + ex = p2x - cx; + ey = p2y - cy; + abs_e = (float)Math.sqrt(ex * ex + ey * ey); + ex /= abs_e; + ey /= abs_e; + GeneralPath bodyPath = new GeneralPath(); + bodyPath.moveTo(p2x + (ey - ex) * adjSize, p2y - (ex + ey) * adjSize); + bodyPath.quadTo(cx, cy, p1x, p1y - bodyWidth / 2); + bodyPath.lineTo(p1x, p1y + bodyWidth / 2); + bodyPath.quadTo(cx, cy, p2x - (ey + ex) * adjSize, p2y + (ex - ey) * adjSize); + bodyPath.closePath(); + + adjSize = (float)(headSize / Math.sqrt(2)); + ex = p2x - cx; + ey = p2y - cy; + abs_e = (float)Math.sqrt(ex * ex + ey * ey); + ex /= abs_e; + ey /= abs_e; + GeneralPath headPath = new GeneralPath(); + headPath.moveTo(p2x - (ey + ex) * adjSize, p2y + (ex - ey) * adjSize); + headPath.lineTo(p2x, p2y); + headPath.lineTo(p2x + (ey - ex) * adjSize, p2y - (ex + ey) * adjSize); + headPath.closePath(); + + Area area = new Area(headPath); + area.add(new Area(bodyPath)); + return area; + } + + private void drawArrow(Graphics2D g2d, int startX, int startY, int endX, int endY, Color color) { + float ex = endX - startX; + float ey = endY - startY; + if (ex == 0 && ey == 0) { return; } + + float length = (float)Math.sqrt(ex * ex + ey * ey); + float bendPercent = (float)Math.asin(ey / length); + + if (endX > startX) bendPercent = -bendPercent; + + Area arrow = getArrow(length, bendPercent); + AffineTransform af = g2d.getTransform(); + + g2d.translate(startX, startY); + g2d.rotate(Math.atan2(ey, ex)); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f)); + g2d.setColor(color); + g2d.fill(arrow); + g2d.setColor(Color.BLACK); + g2d.draw(arrow); + + g2d.setTransform(af); + } + @Override public void paintComponent(final Graphics g) { // No need for this except in match view @@ -160,38 +241,35 @@ public enum TargetingOverlay { // Arc drawing Graphics2D g2d = (Graphics2D) g; - g2d.setColor(FSkin.getColor(FSkin.Colors.CLR_ACTIVE)); - g2d.setStroke(new BasicStroke(3F)); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); assembleArcs(); if (arcs.size() < 1) { return; } + for (Point[] p : arcs) { if (p[0] == null || p[1] == null) { continue; } - double SX = p[0].getX(); - double SY = p[0].getY(); - double CX = p[0].getY() > p[1].getY() ? - Math.max(p[0].getX(), p[1].getX()) * 0.33 + - Math.min(p[0].getX(), p[1].getX()) * 0.66 : - Math.min(p[0].getX(), p[1].getX()) * 0.33 + - Math.max(p[0].getX(), p[1].getX()) * 0.66; - double CY = Math.min(p[0].getY(), p[1].getY()); - double EX = p[1].getX(); - double EY = p[1].getY(); - QuadCurve2D curve = new QuadCurve2D.Double(SX, SY, CX, CY, EX, EY); + if (rectMouseOver != null) { + if ( !rectMouseOver.contains(p[0]) ) { + continue; + } + } - g2d.draw(curve); + int endX = (int)p[0].getX(); + int endY = (int)p[0].getY(); + int startX = (int)p[1].getX(); + int startY = (int)p[1].getY(); - g2d.fillOval((int) p[0].getX() - 4, (int) p[0].getY() - 4, 8, 8); - g2d.fillOval((int) p[1].getX() - 4, (int) p[1].getY() - 4, 8, 8); + Color color = FSkin.getColor(FSkin.Colors.CLR_ACTIVE); + drawArrow(g2d, startX, startY, endX, endY, color); } FView.SINGLETON_INSTANCE.getFrame().repaint(); // repaint the match UI } + } }