diff --git a/forge-gui/CHANGES.txt b/forge-gui/CHANGES.txt index 2463f63e54f..c6a3441e1cb 100644 --- a/forge-gui/CHANGES.txt +++ b/forge-gui/CHANGES.txt @@ -8,6 +8,15 @@ Forge Beta: 0#-##-2014 ver 1.5.15 Release Notes ------------- +- Card Images on Stack - +Each spell/ability on the stack now displays the image for its source card + + +- Layout fixes - +Fixed issue where field would disappear on match screen +Fixed issue where hand pane for player's you've MindSlaved wouldn't be removed after the effect ended + + - The Mac OS application version - We can now package Forge as a Mac OS application. You can double click the Forge.app icon to launch the forge application on your Apple computer running Mac OS. This application will automatically increase the java heap space memory for you as it launches. This version does not require the forge.command file and it does not need to start the Terminal application as part of the start up process. diff --git a/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java b/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java index 2897ae82a36..36cf5675974 100644 --- a/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java +++ b/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java @@ -83,7 +83,6 @@ public enum CSubmenuPreferences implements ICDoc { lstControls.add(Pair.of(view.getCbUseThemes(), FPref.UI_THEMED_COMBOBOX)); lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS)); lstControls.add(Pair.of(view.getCbCompactPrompt(), FPref.UI_COMPACT_PROMPT)); - lstControls.add(Pair.of(view.getCbStackCardView(), FPref.UI_STACK_CARD_VIEW)); lstControls.add(Pair.of(view.getCbHideReminderText(), FPref.UI_HIDE_REMINDER_TEXT)); for(final Pair kv : lstControls) { diff --git a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java index 0a2853884ff..03f7fecccc8 100644 --- a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java +++ b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java @@ -74,7 +74,6 @@ public enum VSubmenuPreferences implements IVSubmenu { private final JCheckBox cbUseThemes = new OptionsCheckBox("Enable Themes"); private final JCheckBox cbPromptFreeBlocks = new OptionsCheckBox("Free Block Handling"); private final JCheckBox cbCompactPrompt = new OptionsCheckBox("Compact Prompt"); - private final JCheckBox cbStackCardView = new OptionsCheckBox("Card View for Stack"); private final JCheckBox cbHideReminderText = new OptionsCheckBox("Hide Reminder Text"); private final Map shortcutFields = new HashMap(); @@ -495,10 +494,6 @@ public enum VSubmenuPreferences implements IVSubmenu { return cbCompactPrompt; } - public final JCheckBox getCbStackCardView() { - return cbStackCardView; - } - public final JCheckBox getCbHideReminderText() { return cbHideReminderText; } diff --git a/forge-gui/src/main/java/forge/gui/match/CMatchUI.java b/forge-gui/src/main/java/forge/gui/match/CMatchUI.java index d4cfc3ad01c..b07566e1034 100644 --- a/forge-gui/src/main/java/forge/gui/match/CMatchUI.java +++ b/forge-gui/src/main/java/forge/gui/match/CMatchUI.java @@ -456,7 +456,6 @@ public enum CMatchUI implements ICDoc, IMenuProvider { for (VCommand c : view.getCommandViews()) { panels.addAll(c.getTabletop().getCardPanels()); } - panels.addAll(VStack.SINGLETON_INSTANCE.getStackArea().getCardPanels()); return panels; } diff --git a/forge-gui/src/main/java/forge/gui/match/views/VStack.java b/forge-gui/src/main/java/forge/gui/match/views/VStack.java index 67c917bec94..0c781e554d1 100644 --- a/forge-gui/src/main/java/forge/gui/match/views/VStack.java +++ b/forge-gui/src/main/java/forge/gui/match/views/VStack.java @@ -17,7 +17,8 @@ */ package forge.gui.match.views; -import forge.Singletons; +import forge.ImageCache; +import forge.game.card.Card; import forge.game.card.CardUtil; import forge.game.player.LobbyPlayer; import forge.game.player.PlayerController; @@ -30,26 +31,21 @@ import forge.gui.framework.IVDoc; import forge.gui.match.CMatchUI; import forge.gui.match.controllers.CStack; import forge.gui.toolbox.FMouseAdapter; -import forge.gui.toolbox.FScrollPane; +import forge.gui.toolbox.FScrollPanel; import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin.SkinnedTextArea; -import forge.properties.ForgePreferences.FPref; -import forge.view.arcane.CardArea; import forge.view.arcane.CardPanel; -import forge.view.arcane.CardPanelContainer; -import forge.view.arcane.util.Animation; import net.miginfocom.swing.MigLayout; import javax.swing.*; -import javax.swing.border.Border; import javax.swing.border.EmptyBorder; + import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.List; +import java.awt.image.BufferedImage; /** * Assembles Swing components of stack report. @@ -62,21 +58,15 @@ public enum VStack implements IVDoc { // Fields used with interface IVDoc private DragCell parentCell; - private boolean cardView; private final DragTab tab = new DragTab("Stack"); // Top-level containers - private final FScrollPane scroller = new FScrollPane(null, true, - ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - private final StackArea stackArea = new StackArea(scroller); + private final FScrollPanel scroller = new FScrollPanel(new MigLayout("insets 1%, gap 1%, wrap"), true); // Other fields - private List stackTARs = new ArrayList(); - private OptionalTriggerMenu otMenu = new OptionalTriggerMenu(); + private static OptionalTriggerMenu otMenu = new OptionalTriggerMenu(); private VStack() { - scroller.setViewportView(stackArea); - stackArea.setOpaque(false); } //========= Overridden methods @@ -86,22 +76,8 @@ public enum VStack implements IVDoc { */ @Override public void populate() { - cardView = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_STACK_CARD_VIEW); - if (cardView) { - final JPanel pnl = parentCell.getBody(); - pnl.setLayout(new MigLayout("insets 0, gap 0")); - - pnl.add(scroller, "w 100%, h 100%!"); - } - } - - /** - * Gets the stack area. - * - * @return {@link forge.gui.match.views.VStack.StackArea} - */ - public StackArea getStackArea() { - return this.stackArea; + parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0")); + parentCell.getBody().add(scroller, "w 100%, h 100%!"); } /* (non-Javadoc) @@ -150,138 +126,130 @@ public enum VStack implements IVDoc { * @param stack * @param viewer */ public void updateStack(final MagicStack stack, final LobbyPlayer viewer) { - // No need to update this unless it's showing - if (!parentCell.getSelected().equals(this)) { return; } - - int count = 1; - Border border = null; - tab.setText("Stack : " + stack.size()); - if (cardView) { - stackArea.clear(); - } - else { - parentCell.getBody().removeAll(); - parentCell.getBody().setLayout(new MigLayout("insets 1%, gap 1%, wrap")); - border = new EmptyBorder(5, 5, 5, 5); - stackTARs.clear(); - } + // No need to update the rest unless it's showing + if (!parentCell.getSelected().equals(this)) { return; } + + scroller.removeAll(); + boolean isFirst = true; for (final SpellAbilityStackInstance spell : stack) { - String isOptional = spell.getSpellAbility().isOptionalTrigger() - && spell.getSourceCard().getController().getController().getLobbyPlayer().equals(viewer) ? "(OPTIONAL) " : ""; - String txt = (count++) + ". " + isOptional + spell.getStackDescription(); + StackInstanceTextArea tar = new StackInstanceTextArea(spell, viewer); - if (cardView) { - Animation.moveCard(stackArea.addCard(spell.getSourceCard())); - } - else { - SkinnedTextArea tar = new SkinnedTextArea(txt); - tar.setToolTipText(txt); - tar.setOpaque(true); - tar.setBorder(border); - this.setSpellColor(tar, spell); + scroller.add(tar, "w 98%!"); - tar.setFocusable(false); - tar.setEditable(false); - tar.setLineWrap(true); - tar.setWrapStyleWord(true); - - /* - * TODO - we should figure out how to display cards on the stack in - * the Picture/Detail panel The problem not is that when a computer - * casts a Morph, the real card shows because Picture/Detail checks - * isFaceDown() which will be false on for spell.getHostCard() on - * the stack. - */ - - // this functionality was present in v 1.1.8 - tar.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(final MouseEvent e) { - if (!spell.getStackDescription().startsWith("Morph ")) { - CMatchUI.SINGLETON_INSTANCE.setCard(spell.getSpellAbility().getHostCard()); - } - } - }); - - if (spell.getSpellAbility().isOptionalTrigger() && spell.getSpellAbility().getActivatingPlayer().getLobbyPlayer() == viewer) { - tar.addMouseListener(new FMouseAdapter() { - @Override - public void onRightClick(MouseEvent e) { - otMenu.setStackInstance(spell); - otMenu.show(e.getComponent(), e.getX(), e.getY()); - } - }); - } - - parentCell.getBody().add(tar, "w 98%!"); - stackTARs.add(tar); - } - - /* - * This updates the Card Picture/Detail when the spell is added to - * the stack. This functionality was not present in v 1.1.8. - * - * Problem is described in TODO right above this. - */ + //update the Card Picture/Detail when the spell is added to the stack if (isFirst) { isFirst = false; - if (!spell.getStackDescription().startsWith("Morph ")) { - CMatchUI.SINGLETON_INSTANCE.setCard(spell.getSourceCard()); - } + CMatchUI.SINGLETON_INSTANCE.setCard(spell.getSourceCard()); } } - if (!cardView) { - parentCell.getBody().validate(); - parentCell.getBody().repaint(); - } + scroller.revalidate(); + scroller.repaint(); } - private void setSpellColor(SkinnedTextArea tar, SpellAbilityStackInstance s0) { - if (s0.getStackDescription().startsWith("Morph ")) { - tar.setBackground(new Color(0, 0, 0, 0)); - tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + @SuppressWarnings("serial") + private static class StackInstanceTextArea extends SkinnedTextArea { + private static final int PADDING = 3; + private static final int CARD_WIDTH = 50; + private static final int CARD_HEIGHT = Math.round((float)CARD_WIDTH * CardPanel.ASPECT_RATIO); + + private final Card sourceCard; + + public StackInstanceTextArea(final SpellAbilityStackInstance spell, final LobbyPlayer viewer) { + sourceCard = spell.getSourceCard(); + + String txt = spell.getStackDescription(); + if (spell.getSpellAbility().isOptionalTrigger() + && spell.getSourceCard().getController().getController().getLobbyPlayer().equals(viewer)) { + txt = "(OPTIONAL) " + txt; + } + setText(txt); + setToolTipText(txt); + setOpaque(true); + setBorder(new EmptyBorder(PADDING, CARD_WIDTH + 2 * PADDING, PADDING, PADDING)); + setFocusable(false); + setEditable(false); + setLineWrap(true); + setWrapStyleWord(true); + setMinimumSize(new Dimension(CARD_WIDTH + 2 * PADDING, CARD_HEIGHT + 2 * PADDING)); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(final MouseEvent e) { + if (!spell.getStackDescription().startsWith("Morph ")) { + CMatchUI.SINGLETON_INSTANCE.setCard(spell.getSpellAbility().getHostCard()); + } + } + }); + + if (spell.getSpellAbility().isOptionalTrigger() && spell.getSpellAbility().getActivatingPlayer().getLobbyPlayer() == viewer) { + addMouseListener(new FMouseAdapter() { + @Override + public void onRightClick(MouseEvent e) { + otMenu.setStackInstance(spell); + otMenu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + } + + if (spell.getStackDescription().startsWith("Morph ")) { + setBackground(new Color(0, 0, 0, 0)); + setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + } + else if (CardUtil.getColors(spell.getSourceCard()).isMulticolor()) { + setBackground(new Color(253, 175, 63)); + setForeground(Color.black); + } + else if (sourceCard.isBlack()) { + setBackground(Color.black); + setForeground(Color.white); + } + else if (sourceCard.isBlue()) { + setBackground(new Color(71, 108, 191)); + setForeground(Color.white); + } + else if (sourceCard.isGreen()) { + setBackground(new Color(23, 95, 30)); + setForeground(Color.white); + } + else if (sourceCard.isRed()) { + setBackground(new Color(214, 8, 8)); + setForeground(Color.white); + } + else if (sourceCard.isWhite()) { + setBackground(Color.white); + setForeground(Color.black); + } + else if (sourceCard.isArtifact() || sourceCard.isLand()) { + setBackground(new Color(111, 75, 43)); + setForeground(Color.white); + } + else { + setBackground(new Color(0, 0, 0, 0)); + setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + } } - else if (CardUtil.getColors(s0.getSourceCard()).isMulticolor()) { - tar.setBackground(new Color(253, 175, 63)); - tar.setForeground(Color.black); - } - else if (s0.getSourceCard().isBlack()) { - tar.setBackground(Color.black); - tar.setForeground(Color.white); - } - else if (s0.getSourceCard().isBlue()) { - tar.setBackground(new Color(71, 108, 191)); - tar.setForeground(Color.white); - } - else if (s0.getSourceCard().isGreen()) { - tar.setBackground(new Color(23, 95, 30)); - tar.setForeground(Color.white); - } - else if (s0.getSourceCard().isRed()) { - tar.setBackground(new Color(214, 8, 8)); - tar.setForeground(Color.white); - } - else if (s0.getSourceCard().isWhite()) { - tar.setBackground(Color.white); - tar.setForeground(Color.black); - } - else if (s0.getSourceCard().isArtifact() || s0.getSourceCard().isLand()) { - tar.setBackground(new Color(111, 75, 43)); - tar.setForeground(Color.white); - } - else { - tar.setBackground(new Color(0, 0, 0, 0)); - tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + final Graphics2D g2d = (Graphics2D) g; + + //draw image for source card + BufferedImage img = ImageCache.getImage(sourceCard, CARD_WIDTH, CARD_HEIGHT); + if (img != null) { + g2d.drawImage(img, null, PADDING, PADDING); + } } } //========= Custom class handling - private final class OptionalTriggerMenu extends JPopupMenu { + private final static class OptionalTriggerMenu extends JPopupMenu { private static final long serialVersionUID = 1548494191627807962L; private final JCheckBoxMenuItem jmiAccept; private final JCheckBoxMenuItem jmiDecline; @@ -291,7 +259,6 @@ public enum VStack implements IVDoc { private Integer triggerID = 0; public OptionalTriggerMenu(){ - jmiAccept = new JCheckBoxMenuItem("Always Accept"); jmiDecline = new JCheckBoxMenuItem("Always Decline"); jmiAsk = new JCheckBoxMenuItem("Always Ask"); @@ -347,95 +314,4 @@ public enum VStack implements IVDoc { } } } - - @SuppressWarnings("serial") - public class StackArea extends CardPanelContainer { - private static final float STACK_SPACING_Y = 0.1f; - - private Dimension size; - - public StackArea(final FScrollPane scrollPane) { - super(scrollPane); - } - - /** {@inheritDoc} */ - @Override - public final void doLayout() { - if (this.getCardPanels().isEmpty()) { - return; - } - - final Rectangle rect = this.getScrollPane().getVisibleRect(); - final Insets insets = this.getScrollPane().getInsets(); - rect.width -= insets.left; - rect.height -= insets.top; - rect.width -= insets.right; - rect.height -= insets.bottom; - - int maxWidth = rect.width - CardArea.GUTTER_X * 2; - int maxHeight = rect.height - CardArea.GUTTER_Y * 2; - int cardWidth = Math.min(maxWidth, this.getCardWidthMax()); - int cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO); - if (cardHeight > maxHeight) { - cardHeight = maxHeight; - cardWidth = Math.round(cardHeight / CardPanel.ASPECT_RATIO); - } - int x = CardArea.GUTTER_X + (maxWidth - cardWidth) / 2; - int y = CardArea.GUTTER_Y; - int cardSpacingY = Math.round(cardHeight * STACK_SPACING_Y); - - List panels = this.getCardPanels(); - for (int i = panels.size() - 1; i >= 0; i--) { - CardPanel panel = panels.get(i); - panel.setCardBounds(x, y, cardWidth, cardHeight); - this.setComponentZOrder(panel, i); - y += cardSpacingY; - } - - maxWidth = rect.width; - maxHeight = Math.max(rect.height, y - cardSpacingY + cardHeight); - final Dimension oldPreferredSize = this.getPreferredSize(); - this.setPreferredSize(new Dimension(maxWidth, maxHeight)); - if ((oldPreferredSize.width != maxWidth) || (oldPreferredSize.height != maxHeight)) { - this.getParent().invalidate(); - this.getParent().validate(); - } - } - - @Override - public final void paint(final Graphics g) { - Dimension newSize = this.getScrollPane().getSize(); - if (this.size == null || !this.size.equals(newSize)) { - if (this.size != null) { - this.revalidate(); - } - this.size = newSize; - } - super.paint(g); - } - - @Override - protected CardPanel getCardPanel(int x, int y) { - // TODO Auto-generated method stub - return null; - } - - /** {@inheritDoc} */ - @Override - public final void mouseOver(final CardPanel panel, final MouseEvent evt) { - super.mouseOver(panel, evt); - } - - /** {@inheritDoc} */ - @Override - public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) { - super.mouseLeftClicked(panel, evt); - } - - /** {@inheritDoc} */ - @Override - public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) { - super.mouseRightClicked(panel, evt); - } - } } diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 29e3b0ed62a..c43c3909f44 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -58,7 +58,6 @@ public class ForgePreferences extends PreferencesStore { UI_SCALE_LARGER ("true"), UI_RANDOM_ART_IN_POOLS ("true"), UI_COMPACT_PROMPT ("false"), - UI_STACK_CARD_VIEW ("false"), UI_CARD_SIZE ("small"), UI_BUGZ_NAME (""), UI_BUGZ_PWD (""),