diff --git a/.gitattributes b/.gitattributes index 6bd5a992322..4589f890809 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12465,6 +12465,7 @@ src/main/java/forge/gui/match/ControlWinLose.java -text src/main/java/forge/gui/match/GauntletWinLose.java -text src/main/java/forge/gui/match/QuestWinLoseCardViewer.java -text src/main/java/forge/gui/match/QuestWinLoseHandler.java -text +src/main/java/forge/gui/match/TargetingOverlay.java -text src/main/java/forge/gui/match/VMatchUI.java -text src/main/java/forge/gui/match/ViewWinLose.java -text src/main/java/forge/gui/match/controllers/CAntes.java -text diff --git a/res/skins/default/sprite_icons.png b/res/skins/default/sprite_icons.png index a0394df0de3..d26a57eb927 100644 Binary files a/res/skins/default/sprite_icons.png and b/res/skins/default/sprite_icons.png differ diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java index 7d440e49abd..113b5a03237 100644 --- a/src/main/java/forge/control/FControl.java +++ b/src/main/java/forge/control/FControl.java @@ -256,11 +256,12 @@ public enum FControl { /** Sizes children of JLayeredPane to fully fit their layers. */ private void sizeChildren() { Component[] children = display.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER); - if (children.length == 0) { return; } - children[0].setSize(display.getSize()); + if (children.length != 0) { children[0].setSize(display.getSize()); } + + children = display.getComponentsInLayer(FView.TARGETING_LAYER); + if (children.length != 0) { children[0].setSize(display.getSize()); } children = display.getComponentsInLayer(JLayeredPane.MODAL_LAYER); - if (children.length == 0) { return; } - children[0].setSize(display.getSize()); + if (children.length != 0) { children[0].setSize(display.getSize()); } } } diff --git a/src/main/java/forge/gui/match/TargetingOverlay.java b/src/main/java/forge/gui/match/TargetingOverlay.java new file mode 100644 index 00000000000..2df29d7e77e --- /dev/null +++ b/src/main/java/forge/gui/match/TargetingOverlay.java @@ -0,0 +1,157 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.gui.match; + +import java.awt.BasicStroke; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JPanel; + +import forge.Card; +import forge.control.FControl; +import forge.gui.match.nonsingleton.CField; +import forge.gui.toolbox.FSkin; +import forge.model.FModel; +import forge.properties.ForgePreferences.FPref; +import forge.view.FView; +import forge.view.arcane.CardPanel; +import forge.view.arcane.PlayArea; + +/** + * Semi-transparent overlay panel. Should be used with layered panes. + * + */ + +@SuppressWarnings("serial") +public enum TargetingOverlay { + /** */ + SINGLETON_INSTANCE; + + private final JPanel pnl = new OverlayPanel(); + private final List playAreas; + private List cardPanels; + private final List arcs = new ArrayList(); + + /** + * Semi-transparent overlay panel. Should be used with layered panes. + */ + private TargetingOverlay() { + playAreas = new ArrayList(); + cardPanels = new ArrayList(); + + for (CField f : CMatchUI.SINGLETON_INSTANCE.getFieldControls()) { + playAreas.add(f.getView().getTabletop()); + } + + pnl.setOpaque(false); + pnl.setBackground(FSkin.getColor(FSkin.Colors.CLR_ZEBRA)); + } + + /** @return {@link javax.swing.JPanel} */ + public JPanel getPanel() { + return this.pnl; + } + + // TODO - this is called every repaint, regardless if card + // positions have changed or not. Could perform better if + // it checked for a state change. Doublestrike 28-09-12 + private void assembleArcs() { + arcs.clear(); + cardPanels.clear(); + cardPanels.addAll(playAreas.get(0).getCardPanels()); + cardPanels.addAll(playAreas.get(1).getCardPanels()); + + final Point docOffsets = FView.SINGLETON_INSTANCE.getLpnDocument().getLocationOnScreen(); + // Locations of arc endpoint, per card, with ID as primary key. + final Map endpoints = new HashMap(); + + // Assemble card locations for easy reference + 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) + )); + } + + List temp = new ArrayList(); + for (CardPanel c : cardPanels) { + if (!c.isShowing()) { continue; } + temp = c.getCard().getEnchantedBy(); + for (Card enchantingCard : temp) { + arcs.add(new Point[] { + endpoints.get(c.getCard().getUniqueNumber()), + endpoints.get(enchantingCard.getUniqueNumber()) + }); + } + } + + temp.clear(); + endpoints.clear(); + } + + private class OverlayPanel extends JPanel { + /** + * For some reason, the alpha channel background doesn't work properly on + * Windows 7, so the paintComponent override is required for a + * semi-transparent overlay. + * + * @param g + *   Graphics object + */ + @Override + public void paintComponent(final Graphics g) { + // No need for this except in match view + if (FControl.SINGLETON_INSTANCE.getState() != 1) { + return; + } + else if (!Boolean.valueOf(FModel.SINGLETON_INSTANCE.getPreferences().getPref(FPref.UI_TARGETING_OVERLAY))) { + return; + } + + super.paintComponent(g); + // 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(); + int w, h, x, y; + + for (Point[] p : arcs) { + w = Math.abs((int) p[1].getX() - (int) p[0].getX()); + h = Math.abs((int) p[1].getY() - (int) p[0].getY()); + x = (Math.min((int) p[1].getX(), (int) p[0].getX()) - w); + y = (Math.min((int) p[1].getY(), (int) p[0].getY())); + + g2d.drawArc(x, y, 2 * w, 2 * h, 0, 90); + 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); + } + } + } +} diff --git a/src/main/java/forge/gui/match/controllers/CDock.java b/src/main/java/forge/gui/match/controllers/CDock.java index e4df86cef64..8678e727ec2 100644 --- a/src/main/java/forge/gui/match/controllers/CDock.java +++ b/src/main/java/forge/gui/match/controllers/CDock.java @@ -47,11 +47,14 @@ import forge.gui.ForgeAction; import forge.gui.SOverlayUtils; import forge.gui.framework.ICDoc; import forge.gui.framework.SLayoutIO; +import forge.gui.match.TargetingOverlay; import forge.gui.match.views.VDock; import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.SaveOpenDialog; import forge.gui.toolbox.SaveOpenDialog.Filetypes; import forge.item.CardPrinted; +import forge.model.FModel; +import forge.properties.ForgePreferences.FPref; import forge.properties.NewConstants; import forge.view.FView; @@ -141,25 +144,39 @@ public enum CDock implements ICDoc { private void viewDeckList() { new DeckListAction(NewConstants.Lang.GuiDisplay.HUMAN_DECKLIST).actionPerformed(null); } - - /** Attack with everyone */ + + /** Attack with everyone. */ public void alphaStrike() { - PhaseHandler ph = Singletons.getModel().getGameState().getPhaseHandler(); - - Player human = AllZone.getHumanPlayer(); - + final PhaseHandler ph = Singletons.getModel().getGameState().getPhaseHandler(); + + final Player human = AllZone.getHumanPlayer(); + if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, human)) { - for(Card c : human.getCardsIn(ZoneType.Battlefield).filter(Presets.CREATURES)) { + for (Card c : human.getCardsIn(ZoneType.Battlefield).filter(Presets.CREATURES)) { if (!c.isAttacking() && CombatUtil.canAttack(c, AllZone.getCombat())) { AllZone.getCombat().addAttacker(c); } } //human.updateObservers(); + // TODO Is this redrawing immediately? FView.SINGLETON_INSTANCE.getFrame().repaint(); } } + /** Toggle targeting overlay painting. */ + public void toggleTargeting() { + if (Boolean.valueOf(FModel.SINGLETON_INSTANCE.getPreferences().getPref(FPref.UI_TARGETING_OVERLAY))) { + FModel.SINGLETON_INSTANCE.getPreferences().setPref(FPref.UI_TARGETING_OVERLAY, "false"); + } + else { + FModel.SINGLETON_INSTANCE.getPreferences().setPref(FPref.UI_TARGETING_OVERLAY, "true"); + } + + FModel.SINGLETON_INSTANCE.getPreferences().save(); + TargetingOverlay.SINGLETON_INSTANCE.getPanel().repaint(); + } + /** * Receives click and programmatic requests for viewing a player's library * (typically used in dev mode). Allows copy of the cardlist to clipboard. @@ -282,11 +299,16 @@ public enum CDock implements ICDoc { .addMouseListener(new MouseAdapter() { @Override public void mousePressed(final MouseEvent e) { saveLayout(); } }); - + VDock.SINGLETON_INSTANCE.getBtnAlphaStrike() .addMouseListener(new MouseAdapter() { @Override public void mousePressed(final MouseEvent e) { alphaStrike(); } }); + + VDock.SINGLETON_INSTANCE.getBtnTargeting() + .addMouseListener(new MouseAdapter() { @Override + public void mousePressed(final MouseEvent e) { + toggleTargeting(); } }); } /* (non-Javadoc) diff --git a/src/main/java/forge/gui/match/views/VDock.java b/src/main/java/forge/gui/match/views/VDock.java index bcc5f842bce..59b042f1302 100644 --- a/src/main/java/forge/gui/match/views/VDock.java +++ b/src/main/java/forge/gui/match/views/VDock.java @@ -67,6 +67,8 @@ public enum VDock implements IVDoc { new DockButton(FSkin.getIcon(FSkin.DockIcons.ICO_SAVELAYOUT), "Save Layout"); private final JLabel btnAlphaStrike = new DockButton(FSkin.getIcon(FSkin.DockIcons.ICO_ALPHASTRIKE), "Alpha Strike"); + private final JLabel btnTargeting = + new DockButton(FSkin.getIcon(FSkin.DockIcons.ICO_TARGETING), "Show Targeting Arcs"); //========= Overridden methods @@ -88,6 +90,7 @@ public enum VDock implements IVDoc { pnl.add(btnOpenLayout); pnl.add(btnSaveLayout); pnl.add(btnAlphaStrike); + pnl.add(btnTargeting); } /* (non-Javadoc) @@ -172,6 +175,11 @@ public enum VDock implements IVDoc { return btnAlphaStrike; } + /** @return {@link javax.swing.JLabel} */ + public JLabel getBtnTargeting() { + return btnTargeting; + } + //========= Custom class handling /** * Buttons in Dock. JLabels are used to allow hover effects. diff --git a/src/main/java/forge/gui/toolbox/FSkin.java b/src/main/java/forge/gui/toolbox/FSkin.java index 0f0b0ecf689..e350c86f08a 100644 --- a/src/main/java/forge/gui/toolbox/FSkin.java +++ b/src/main/java/forge/gui/toolbox/FSkin.java @@ -227,7 +227,8 @@ public enum FSkin { ICO_OPENLAYOUT (new int[] {0, 800, 80, 80}), /** */ ICO_SAVELAYOUT (new int[] {80, 800, 80, 80}), /** */ ICO_DECKLIST (new int[] {400, 640, 80, 80}), /** */ - ICO_ALPHASTRIKE (new int[] {160, 800, 80, 80}); + ICO_ALPHASTRIKE (new int[] {160, 800, 80, 80}), /** */ + ICO_TARGETING (new int[] {240, 800, 80, 80}); private int[] coords; /** @param xy   int[] coordinates */ diff --git a/src/main/java/forge/properties/ForgePreferences.java b/src/main/java/forge/properties/ForgePreferences.java index 82a036002a0..03a868d8400 100644 --- a/src/main/java/forge/properties/ForgePreferences.java +++ b/src/main/java/forge/properties/ForgePreferences.java @@ -67,6 +67,7 @@ public class ForgePreferences { UI_MANABURN("false"), /** */ UI_SKIN ("default"), /** */ UI_PREFERRED_AVATARS_ONLY ("false"), /** */ + UI_TARGETING_OVERLAY ("false"), /** */ SUBMENU_CURRENTMENU (EMenuItem.CONSTRUCTED.toString()), /** */ SUBMENU_SANCTIONED ("false"), /** */ diff --git a/src/main/java/forge/view/FView.java b/src/main/java/forge/view/FView.java index 203da9b9389..987e4c2c1ed 100644 --- a/src/main/java/forge/view/FView.java +++ b/src/main/java/forge/view/FView.java @@ -24,6 +24,7 @@ import forge.gui.framework.EDocID; import forge.gui.framework.SLayoutConstants; import forge.gui.home.CMainMenu; import forge.gui.home.VHomeUI; +import forge.gui.match.TargetingOverlay; import forge.gui.match.VMatchUI; import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.FPanel; @@ -33,6 +34,9 @@ import forge.gui.toolbox.FSkin; public enum FView { /** */ SINGLETON_INSTANCE; + + /** */ + public static final Integer TARGETING_LAYER = JLayeredPane.MODAL_LAYER - 1; private final List allCells = new ArrayList(); private SplashFrame splash; @@ -73,6 +77,10 @@ public enum FView { lpnDocument.add(pnlPreview, (Integer) 2); lpnDocument.add(pnlTabOverflow, (Integer) 3); lpnDocument.add(FOverlay.SINGLETON_INSTANCE.getPanel(), JLayeredPane.MODAL_LAYER); + // Note: when adding new panels here, keep in mind that the layered pane + // has a null layout, so new components will be (0,0) - gotcha! + // FControl has a method called "sizeComponents" which will fix this. + lpnDocument.add(TargetingOverlay.SINGLETON_INSTANCE.getPanel(), TARGETING_LAYER); pnlInsets.add(pnlContent, BorderLayout.CENTER); pnlInsets.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE));