diff --git a/Mage.Client/plugins/mage-card-plugin.jar b/Mage.Client/plugins/mage-card-plugin.jar index a7db7a9f45..53cd6661aa 100644 Binary files a/Mage.Client/plugins/mage-card-plugin.jar and b/Mage.Client/plugins/mage-card-plugin.jar differ diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index bf4a607f9b..f141f9908d 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -34,6 +34,7 @@ package mage.client; +import mage.cards.Card; import mage.cards.decks.Deck; import mage.client.cards.CardsStorage; import mage.client.components.MageComponents; @@ -41,6 +42,7 @@ import mage.client.components.MageJDesktop; import mage.client.components.MageRoundPane; import mage.client.components.arcane.ManaSymbols; import mage.client.constants.Constants.DeckEditorMode; +import mage.client.deckeditor.collection.viewer.CollectionViewerPane; import mage.client.dialog.*; import mage.client.plugins.impl.Plugins; import mage.client.remote.Session; @@ -61,6 +63,7 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.UUID; import java.util.logging.Level; @@ -122,6 +125,7 @@ public class MageFrame extends javax.swing.JFrame { } Plugins.getInstance().loadPlugins(); + ManaSymbols.loadImages(); initComponents(); setSize(1024, 768); @@ -137,8 +141,6 @@ public class MageFrame extends javax.swing.JFrame { desktopPane.add(pickNumber, JLayeredPane.POPUP_LAYER); session.getUI().addComponent(MageComponents.DESKTOP_PANE, desktopPane); - ManaSymbols.loadImages(); - addTooltipContainer(); setBackground(); addMageLabel(); @@ -287,7 +289,7 @@ public class MageFrame extends javax.swing.JFrame { } private void btnImagesActionPerformed(java.awt.event.ActionEvent evt) { - Plugins.getInstance().downloadImage(CardsStorage.getAllCards()); + Plugins.getInstance().downloadImage(new HashSet<Card>(CardsStorage.getAllCards())); } private void btnSymbolsActionPerformed(java.awt.event.ActionEvent evt) { @@ -355,6 +357,7 @@ public class MageFrame extends javax.swing.JFrame { tablesPane = new mage.client.table.TablesPane(); gamePane = new mage.client.game.GamePane(); deckEditorPane = new mage.client.deckeditor.DeckEditorPane(); + collectionViewerPane = new CollectionViewerPane(); mageToolbar = new javax.swing.JToolBar(); btnConnect = new javax.swing.JButton(); jSeparator5 = new javax.swing.JToolBar.Separator(); @@ -368,11 +371,12 @@ public class MageFrame extends javax.swing.JFrame { jSeparator1 = new javax.swing.JToolBar.Separator(); btnExit = new javax.swing.JButton(); lblStatus = new javax.swing.JLabel(); + jSeparator6 = new javax.swing.JToolBar.Separator(); + btnCollectionViewer = new JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); //setMinimumSize(new java.awt.Dimension(1024, 768)); - //desktopPane.setBackground(new java.awt.Color(204, 204, 204)); tablesPane.setBounds(20, 10, 560, 440); desktopPane.add(tablesPane, javax.swing.JLayeredPane.DEFAULT_LAYER); try { @@ -394,6 +398,13 @@ public class MageFrame extends javax.swing.JFrame { } catch (java.beans.PropertyVetoException e1) { e1.printStackTrace(); } + collectionViewerPane.setBounds(140, 50, -1, -1); + desktopPane.add(collectionViewerPane, javax.swing.JLayeredPane.DEFAULT_LAYER); + try { + collectionViewerPane.setMaximum(true); + } catch (java.beans.PropertyVetoException e1) { + e1.printStackTrace(); + } mageToolbar.setFloatable(false); mageToolbar.setRollover(true); @@ -437,6 +448,19 @@ public class MageFrame extends javax.swing.JFrame { mageToolbar.add(btnDeckEditor); mageToolbar.add(jSeparator2); + btnCollectionViewer.setText("Collection Viewer"); + btnCollectionViewer.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); + btnCollectionViewer.setFocusable(false); + btnCollectionViewer.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnCollectionViewer.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnCollectionViewer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCollectionViewerActionPerformed(evt); + } + }); + mageToolbar.add(btnCollectionViewer); + mageToolbar.add(jSeparator6); + btnPreferences.setText("Preferences"); btnPreferences.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); btnPreferences.setFocusable(false); @@ -500,9 +524,17 @@ public class MageFrame extends javax.swing.JFrame { private void btnDeckEditorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeckEditorActionPerformed this.gamePane.setVisible(false); this.tablesPane.setVisible(false); + this.collectionViewerPane.setVisible(false); showDeckEditor(DeckEditorMode.Constructed, null, null); }//GEN-LAST:event_btnDeckEditorActionPerformed + private void btnCollectionViewerActionPerformed(java.awt.event.ActionEvent evt) { + this.gamePane.setVisible(false); + this.tablesPane.setVisible(false); + this.deckEditorPane.setVisible(false); + showCollectionViewer(); + } + private void btnPreferencesActionPerformed(java.awt.event.ActionEvent evt) { PhasesDialog.main(new String[]{}); } @@ -510,6 +542,7 @@ public class MageFrame extends javax.swing.JFrame { private void btnGamesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGamesActionPerformed this.gamePane.setVisible(false); this.deckEditorPane.setVisible(false); + this.collectionViewerPane.setVisible(false); this.tablesPane.setVisible(true); this.tablesPane.showTables(); }//GEN-LAST:event_btnGamesActionPerformed @@ -556,6 +589,7 @@ public class MageFrame extends javax.swing.JFrame { this.tablesPane.setVisible(false); this.gamePane.setVisible(false); this.deckEditorPane.setVisible(false); + this.collectionViewerPane.setVisible(false); } public void showDeckEditor(DeckEditorMode mode, Deck deck, UUID tableId) { @@ -563,6 +597,10 @@ public class MageFrame extends javax.swing.JFrame { this.deckEditorPane.show(mode, deck, tableId); } + public void showCollectionViewer() { + this.collectionViewerPane.setVisible(true); + } + public static CombatDialog getCombatDialog() { return combat; } @@ -608,10 +646,12 @@ public class MageFrame extends javax.swing.JFrame { private javax.swing.JButton btnAbout; private javax.swing.JButton btnConnect; private javax.swing.JButton btnDeckEditor; + private javax.swing.JButton btnCollectionViewer; private javax.swing.JButton btnPreferences; private javax.swing.JButton btnExit; private javax.swing.JButton btnGames; private mage.client.deckeditor.DeckEditorPane deckEditorPane; + private CollectionViewerPane collectionViewerPane; private static MageJDesktop desktopPane; private mage.client.game.GamePane gamePane; private javax.swing.JToolBar.Separator jSeparator1; @@ -619,6 +659,7 @@ public class MageFrame extends javax.swing.JFrame { private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; private javax.swing.JToolBar.Separator jSeparator5; + private javax.swing.JToolBar.Separator jSeparator6; private javax.swing.JLabel lblStatus; private javax.swing.JToolBar mageToolbar; private mage.client.table.TablesPane tablesPane; diff --git a/Mage.Client/src/main/java/mage/client/cards/BigCard.java b/Mage.Client/src/main/java/mage/client/cards/BigCard.java index 76837ee626..769d347041 100644 --- a/Mage.Client/src/main/java/mage/client/cards/BigCard.java +++ b/Mage.Client/src/main/java/mage/client/cards/BigCard.java @@ -69,9 +69,9 @@ public class BigCard extends JComponent { protected float hue = 0.005f; protected float dh = 0.005f; - static private final int DEFAULT_DELAY_PERIOD = 40; + static private final int DEFAULT_DELAY_PERIOD = 30; static private final float LEFT_BOUNDARY = 0.0f; - static private final float RIGHT_BOUNDARY = 0.1f; + static private final float RIGHT_BOUNDARY = 1f; public BigCard() { initComponents(); @@ -247,6 +247,7 @@ public class BigCard extends JComponent { setFocusable(false); setMinimumSize(new Dimension(FRAME_MAX_WIDTH, FRAME_MAX_HEIGHT)); + setMaximumSize(new Dimension(FRAME_MAX_WIDTH, FRAME_MAX_HEIGHT)); setOpaque(false); setPreferredSize(getMinimumSize()); setLayout(null); diff --git a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java index f15687451d..d82e4f72dd 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java @@ -93,7 +93,7 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener } private void addCard(CardView card, BigCard bigCard, UUID gameId) { - MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId); + MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId, true); cards.put(card.getId(), cardImg); cardImg.addMouseListener(this); add(cardImg); diff --git a/Mage.Client/src/main/java/mage/client/cards/Cards.java b/Mage.Client/src/main/java/mage/client/cards/Cards.java index ee0c38dc97..f98722137b 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Cards.java +++ b/Mage.Client/src/main/java/mage/client/cards/Cards.java @@ -120,7 +120,7 @@ public class Cards extends javax.swing.JPanel { } private void addCard(CardView card, BigCard bigCard, UUID gameId) { - MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId); + MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId, true); cards.put(card.getId(), cardImg); cardArea.add(cardImg); } diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.java b/Mage.Client/src/main/java/mage/client/cards/CardsList.java index c386a18da9..6aa6b0cd43 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.java @@ -101,7 +101,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener { } private void addCard(CardView card, BigCard bigCard, UUID gameId, Rectangle rectangle) { - MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId); + MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, Config.dimensions, gameId, true); cardImg.setBounds(rectangle); cardArea.add(cardImg); cardArea.moveToFront(cardImg); diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsStorage.java b/Mage.Client/src/main/java/mage/client/cards/CardsStorage.java index 036bacd350..8d5b2d5c56 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsStorage.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardsStorage.java @@ -1,93 +1,193 @@ package mage.client.cards; -import java.io.InputStream; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; - import mage.cards.Card; import mage.cards.ExpansionSet; import mage.sets.Sets; import mage.utils.CardUtil; +import java.io.InputStream; +import java.util.*; + +/** + * Stores all implemented cards on client side. + * Used by deck editor, deck generator, collection viewer, etc. + * + * @author nantuko + */ public class CardsStorage { - private static Set<Card> allCards = new LinkedHashSet<Card>(); - private static Set<Card> nonBasicLandCards = new LinkedHashSet<Card>(); - private static Map<String, Integer> ratings; - private static Integer min = Integer.MAX_VALUE, max = 0; + private static List<Card> allCards = new ArrayList<Card>(); + private static Set<Card> nonBasicLandCards = new LinkedHashSet<Card>(); + private static Map<String, Integer> ratings; + private static Integer min = Integer.MAX_VALUE, max = 0; + private static int cardsCount; + private static List<String> setCodes = new ArrayList<String>(); - static { - for (ExpansionSet set : Sets.getInstance().values()) { - Set<Card> cards = set.createCards(); - allCards.addAll(cards); - for (Card card : cards) { - if (CardUtil.isLand(card) && !CardUtil.isBasicLand(card)) { - nonBasicLandCards.add(card); - } - } - } - } + static { + for (ExpansionSet set : Sets.getInstance().values()) { + setCodes.add(set.getCode()); + Set<Card> cards = set.createCards(); + allCards.addAll(cards); + for (Card card : cards) { + if (CardUtil.isLand(card) && !CardUtil.isBasicLand(card)) { + nonBasicLandCards.add(card); + } + } + } + Collections.sort(allCards, new CardComparator()); + Collections.sort(setCodes, new SetComparator()); + cardsCount = allCards.size(); + } - public static Set<Card> getAllCards() { - return allCards; - } + public static List<Card> getAllCards() { + return allCards; + } - public static Set<Card> getNonBasicLandCards() { - return nonBasicLandCards; - } + /** + * Get cards from card pool starting from start index and ending with end index. + * Can filter cards by set (if parameter is not null). + * + * @param start + * @param end + * @param set Cards set code. Can be null. + * @return + */ + public static List<Card> getAllCards(int start, int end, String set) { + List<Card> cards = new ArrayList<Card>(); + List<Card> pool; + if (set == null) { + pool = allCards; + } else { + pool = new ArrayList<Card>(); + for (Card card : allCards) { + if (card.getExpansionSetCode().equals(set)) { + pool.add(card); + } + } + } + for (int i = start; i < Math.min(end + 1, pool.size()); i++) { + cards.add(pool.get(i)); + } + return cards; + } - /** - * Return rating of a card: 1-10. - * - * @param card - * @return - */ - public static int rateCard(Card card) { - if (ratings == null) { - readRatings(); - } - if (ratings.containsKey(card.getName())) { - int r = ratings.get(card.getName()); - float f = 10.0f * (r - min) / (max - min); - return (int)Math.round(f); // normalize to [1..10] - } - return 0; - } - - private synchronized static void readRatings() { - if (ratings == null) { - ratings = new HashMap<String, Integer>(); - String filename = "/ratings.txt"; - try { - InputStream is = CardsStorage.class.getResourceAsStream(filename); - Scanner scanner = new Scanner(is); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - String[] s = line.split(":"); - if (s.length == 2) { - Integer rating = Integer.parseInt(s[0].trim()); - String name = s[1].trim(); - if (rating > max) { max = rating; } - if (rating < min) { min = rating; } - ratings.put(name, rating); - } - } - } catch (Exception e) { - e.printStackTrace(); - ratings.clear(); // no rating available on exception - } - } - } + public static int getCardsCount() { + return cardsCount; + } - public static void main(String[] argv) { - for (Card card : getAllCards()) { - String name = card.getName(); - if (name.equals("Baneslayer Angel") || name.equals("Lightning Bolt") || name.equals("Zombie Outlander") - || name.equals("Naturalize") || name.equals("Kraken's Eye") || name.equals("Serra Angel")) { - System.out.println(name + " : " + rateCard(card)); - } - } - } + public static List<String> getSetCodes() { + return setCodes; + } + + public static Set<Card> getNonBasicLandCards() { + return nonBasicLandCards; + } + + /** + * Return rating of a card: 1-10. + * + * @param card + * @return + */ + public static int rateCard(Card card) { + if (ratings == null) { + readRatings(); + } + if (ratings.containsKey(card.getName())) { + int r = ratings.get(card.getName()); + float f = 10.0f * (r - min) / (max - min); + return (int) Math.round(f); // normalize to [1..10] + } + return 0; + } + + private synchronized static void readRatings() { + if (ratings == null) { + ratings = new HashMap<String, Integer>(); + String filename = "/ratings.txt"; + try { + InputStream is = CardsStorage.class.getResourceAsStream(filename); + Scanner scanner = new Scanner(is); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + String[] s = line.split(":"); + if (s.length == 2) { + Integer rating = Integer.parseInt(s[0].trim()); + String name = s[1].trim(); + if (rating > max) { + max = rating; + } + if (rating < min) { + min = rating; + } + ratings.put(name, rating); + } + } + } catch (Exception e) { + e.printStackTrace(); + ratings.clear(); // no rating available on exception + } + } + } + + public static void main(String[] argv) { + for (Card card : getAllCards()) { + String name = card.getName(); + if (name.equals("Baneslayer Angel") || name.equals("Lightning Bolt") || name.equals("Zombie Outlander") + || name.equals("Naturalize") || name.equals("Kraken's Eye") || name.equals("Serra Angel")) { + System.out.println(name + " : " + rateCard(card)); + } + } + } + + /** + * Card comparator. + * First compares set codes, then collector ids and just then card names. + * <p/> + * Show latest set cards on top. + * + * @author nantuko + */ + private static class CardComparator implements Comparator<Card> { + private static final String LATEST_SET_CODE = "SOM"; + + @Override + public int compare(Card o1, Card o2) { + String set1 = o1.getExpansionSetCode(); + String set2 = o2.getExpansionSetCode(); + if (set1.equals(set2)) { + Integer cid1 = o1.getCardNumber(); + Integer cid2 = o2.getCardNumber(); + if (cid1 == cid2) { + return o1.getName().compareTo(o2.getName()); + } else { + return cid1.compareTo(cid2); + } + } else { + // put latest set on top + if (set1.equals(LATEST_SET_CODE)) { + return -1; + } + if (set2.equals(LATEST_SET_CODE)) { + return 1; + } + return set1.compareTo(set2); + } + } + } + + private static class SetComparator implements Comparator<String> { + private static final String LATEST_SET_CODE = "SOM"; + + @Override + public int compare(String set1, String set2) { + // put latest set on top + if (set1.equals(LATEST_SET_CODE)) { + return -1; + } + if (set2.equals(LATEST_SET_CODE)) { + return 1; + } + return set1.compareTo(set2); + } + } } diff --git a/Mage.Client/src/main/java/mage/client/components/HoverButton.java b/Mage.Client/src/main/java/mage/client/components/HoverButton.java new file mode 100644 index 0000000000..83dab1f3a8 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/HoverButton.java @@ -0,0 +1,171 @@ +package mage.client.components; + +import mage.client.util.Command; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.font.FontRenderContext; + +/** + * Image button with hover. + * + * @author nantuko + */ +public class HoverButton extends JPanel implements MouseListener { + + private Image image; + private Image hoverImage; + private Image disabledImage; + private Image selectedImage; + private Image overlayImage; + private Rectangle imageSize; + private Rectangle buttonSize; + private String text; + private int textOffsetY = 0; + private int textOffsetX = -1; + private Dimension overlayImageSize; + + private boolean isHovered = false; + private boolean isSelected = false; + + private Command observer = null; + private Command onHover = null; + private Color textColor = Color.white; + + final static Font textFont = new Font("Arial", Font.PLAIN, 12); + final static Font textFontMini = new Font("Arial", Font.PLAIN, 11); + private boolean useMiniFont = false; + + public HoverButton(String text, Image image, Image hover, Image disabled, Rectangle size) { + this(text, image, hover, null, disabled, size); + } + + public HoverButton(String text, Image image, Image hover, Image selected, Image disabled, Rectangle size) { + this.image = image; + this.hoverImage = hover; + this.selectedImage = selected; + this.disabledImage = disabled; + this.imageSize = size; + this.text = text; + setOpaque(false); + addMouseListener(this); + } + + @Override + public void paintComponent(Graphics g) { + if (isEnabled()) { + if (isHovered) { + g.drawImage(hoverImage, 0, 0, imageSize.width, imageSize.height, this); + if (text != null) { + Graphics2D g2d = (Graphics2D) g; + if (textColor != null) g2d.setColor(textColor); + if (useMiniFont) g2d.setFont(textFontMini); + else g2d.setFont(textFont); + if (textOffsetX == -1) { // calculate once + FontRenderContext frc = g2d.getFontRenderContext(); + int textWidth = (int) textFont.getStringBounds(text, frc).getWidth(); + if (textWidth > buttonSize.width) { + g2d.setFont(textFontMini); + useMiniFont = true; + frc = g2d.getFontRenderContext(); + textWidth = (int) textFontMini.getStringBounds(text, frc).getWidth(); + } + textOffsetX = (int) ((imageSize.width - textWidth) / 2); + } + g2d.drawString(text, textOffsetX, textOffsetY); + } + } else { + g.drawImage(image, 0, 0, imageSize.width, imageSize.height, this); + } + if (isSelected) { + if (selectedImage != null) { + g.drawImage(selectedImage, 0, 0, imageSize.width, imageSize.height, this); + } else { + System.err.println("No selectedImage for button."); + } + } + } else { + g.drawImage(disabledImage, 0, 0, imageSize.width, imageSize.height, this); + } + if (overlayImage != null) { + g.drawImage(overlayImage, (imageSize.width - overlayImageSize.width) / 2, 10, this); + } + } + + public void setTextColor(Color textColor) { + this.textColor = textColor; + } + + public void setOverlayImage(Image image) { + this.overlayImage = image; + this.overlayImageSize = new Dimension(image.getWidth(null), image.getHeight(null)); + } + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + isHovered = true; + this.repaint(); + if (onHover != null) { + onHover.execute(); + } + } + + @Override + public void mouseExited(MouseEvent e) { + isHovered = false; + this.repaint(); + } + + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (isEnabled() && observer != null) { + observer.execute(); + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + } + + public void setObserver(Command observer) { + this.observer = observer; + } + + public void setOnHover(Command onHover) { + this.onHover = onHover; + } + + @Override + public void setBounds(Rectangle r) { + super.setBounds(r); + this.textOffsetY = r.height - 2; + this.buttonSize = r; + } + + @Override + public void setBounds(int x, int y, int width, int height) { + super.setBounds(x, y, width, height); + this.textOffsetY = height - 2; + this.buttonSize = new Rectangle(x, y, width, height); + } + + public boolean isSelected() { + return isSelected; + } + + public void setSelected(boolean isSelected) { + this.isSelected = isSelected; + } + + public void changeSelected() { + this.isSelected = !this.isSelected; + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/ImageButton.java b/Mage.Client/src/main/java/mage/client/components/ImageButton.java new file mode 100644 index 0000000000..96836c32de --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ImageButton.java @@ -0,0 +1,59 @@ +package mage.client.components; + +import javax.swing.*; +import java.awt.*; + +/** + * Image based button. + * + * @author nantuko + */ +public class ImageButton extends JButton { + + private Image image; + private String text; + + public ImageButton(String text, Image image) { + super(new ImageIcon(image)); + this.image = image; + this.text = text; + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + if (text != null) { + g.setColor(Color.GRAY); + int dx = 15; + int dy = 17; + g.setColor(Color.WHITE); + if (text.length() > 5) { + g.drawString(this.text, 8, dy); + } else { + g.drawString(this.text, dx, dy); + } + } + } + + public void setImage(Image src) { + this.image = src; + repaint(); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(image.getWidth(this), image.getHeight(this)); + } + + @Override + public Dimension getMinimumSize() { + return new Dimension(image.getWidth(this), image.getHeight(this)); + } + + @Override + public void setText(String text) { + this.text = text; + repaint(); + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/arcane/GlowText.java b/Mage.Client/src/main/java/mage/client/components/arcane/GlowText.java new file mode 100644 index 0000000000..0a92f2565f --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/arcane/GlowText.java @@ -0,0 +1,96 @@ +package mage.client.components.arcane; + +import javax.swing.*; +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.text.BreakIterator; +import java.util.Locale; + +public class GlowText extends JLabel { + private static final long serialVersionUID = 1827677946939348001L; + private int glowSize; + @SuppressWarnings("unused") + private float glowIntensity; + private Color glowColor; + private boolean wrap; + private int lineCount = 0; + + public void setGlow (Color glowColor, int size, float intensity) { + this.glowColor = glowColor; + this.glowSize = size; + this.glowIntensity = intensity; + } + + public void setWrap (boolean wrap) { + this.wrap = wrap; + } + + public Dimension getPreferredSize () { + Dimension size = super.getPreferredSize(); + size.width += glowSize; + size.height += glowSize / 2; + return size; + } + + public void setText (String text) { + super.setText(text); + } + + public void paint (Graphics g) { + if (getText().length() == 0) return; + + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + Dimension size = getSize(); + int textX = 0, textY = 0; + int wrapWidth = Math.max(0, wrap ? size.width - glowSize : Integer.MAX_VALUE); + + AttributedString attributedString = new AttributedString(getText()); + attributedString.addAttribute(TextAttribute.FONT, getFont()); + AttributedCharacterIterator charIterator = attributedString.getIterator(); + FontRenderContext fontContext = g2d.getFontRenderContext(); + + LineBreakMeasurer measurer = new LineBreakMeasurer(charIterator, BreakIterator.getWordInstance(Locale.ENGLISH), fontContext); + lineCount = 0; + while (measurer.getPosition() < charIterator.getEndIndex()) { + //TextLayout textLayout = measurer.nextLayout(wrapWidth); + lineCount++; + if (lineCount > 2) break; + } + charIterator.first(); + // Use char wrap if word wrap would cause more than two lines of text. + if (lineCount > 2) + measurer = new LineBreakMeasurer(charIterator, BreakIterator.getCharacterInstance(Locale.ENGLISH), fontContext); + else + measurer.setPosition(0); + while (measurer.getPosition() < charIterator.getEndIndex()) { + TextLayout textLayout = measurer.nextLayout(wrapWidth); + float ascent = textLayout.getAscent(); + textY += ascent; // Move down to baseline. + + g2d.setColor(glowColor); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f)); + textLayout.draw(g2d, textX + glowSize / 2 + 1, textY + glowSize / 2 - 1); + textLayout.draw(g2d, textX + glowSize / 2 + 1, textY + glowSize / 2 + 1); + textLayout.draw(g2d, textX + glowSize / 2 - 1, textY + glowSize / 2 - 1); + textLayout.draw(g2d, textX + glowSize / 2 - 1, textY + glowSize / 2 + 1); + + g2d.setColor(getForeground()); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); + textLayout.draw(g2d, textX + glowSize / 2, textY + glowSize / 2); + + textY += textLayout.getDescent() + textLayout.getLeading(); // Move down to top of next line. + } + } + + public int getLineCount() { + return this.lineCount; + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java b/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java index 9526ad1e2d..fce8a1d66d 100644 --- a/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/mage/client/components/arcane/ManaSymbols.java @@ -1,5 +1,6 @@ package mage.client.components.arcane; +import mage.client.cards.CardsStorage; import mage.client.constants.Constants; import mage.client.util.gui.BufferedImageBuilder; import mage.client.util.gui.ImageResizeUtil; @@ -18,6 +19,7 @@ public class ManaSymbols { private static final Logger log = Logger.getLogger(ManaSymbols.class); static private final Map<String, Image> manaImages = new HashMap<String, Image>(); static private final Map<String, Image> manaImagesOriginal = new HashMap<String, Image>(); + static private final Map<String, Image> setImages = new HashMap<String, Image>(); static private Pattern replaceSymbolsPattern = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}"); static private boolean noManaSymbols = false; @@ -40,11 +42,33 @@ public class ManaSymbols { manaImagesOriginal.put(symbol, image); } catch (Exception e) {} } + for (String set : CardsStorage.getSetCodes()) { + String _set = set.equals("CON") ? "CFX" : set; + File file = new File(Constants.RESOURCE_PATH_SET + _set + ".jpg"); + try { + Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); + int width = image.getWidth(null); + if (width > 21) { + int h = image.getHeight(null); + if (h > 0) { + Rectangle r = new Rectangle(21, (int)(h * 21.0f / width)); + BufferedImage resized = ImageResizeUtil.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); + setImages.put(set, resized); + } + } else { + setImages.put(set, image); + } + } catch (Exception e) {} + } } static public Image getManaSymbolImage(String symbol) { return manaImagesOriginal.get(symbol); } + + static public Image getSetSymbolImage(String set) { + return setImages.get(set); + } static public void draw (Graphics g, String manaCost, int x, int y) { if (manaCost.length() == 0) return; diff --git a/Mage.Client/src/main/java/mage/client/constants/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java index a91617ed20..0d583e1860 100644 --- a/Mage.Client/src/main/java/mage/client/constants/Constants.java +++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java @@ -77,6 +77,7 @@ public final class Constants { public static final String RESOURCE_PATH_MANA_LARGE = IO.imageBaseDir + "symbols" + File.separator + "large"; public static final String RESOURCE_PATH_MANA_MEDIUM = IO.imageBaseDir + "symbols" + File.separator + "medium"; + public static final String RESOURCE_PATH_SET = IO.imageBaseDir + "sets" + File.separator; public interface IO { public static final String imageBaseDir = "plugins" + File.separator + "images" + File.separator; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPane.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPane.java new file mode 100644 index 0000000000..3f9946f323 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPane.java @@ -0,0 +1,86 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ +package mage.client.deckeditor.collection.viewer; + +import mage.client.MagePane; +import mage.client.plugins.impl.Plugins; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.util.HashMap; +import java.util.Map; + +/** + * Collection viewer pane. + * Contains background and components container. + * + * @author nantuko + */ +public class CollectionViewerPane extends MagePane { + + public CollectionViewerPane() { + boolean initialized = false; + if (Plugins.getInstance().isThemePluginLoaded()) { + Map<String, JComponent> ui = new HashMap<String, JComponent>(); + JComponent container = Plugins.getInstance().updateTablePanel(ui); + if (container != null) { + collectionViewerPanel = new CollectionViewerPanel(); + initComponents(container); + container.add(collectionViewerPanel); + container.setOpaque(false); + collectionViewerPanel.setOpaque(false); + initialized = true; + } + } + if (!initialized) { + initComponents(null); + } + } + + private void initComponents(Component container) { + Component component = container != null ? container : collectionViewerPanel; + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(component, javax.swing.GroupLayout.DEFAULT_SIZE, 885, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(component, javax.swing.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE) + ); + + pack(); + } + + private CollectionViewerPanel collectionViewerPanel; +} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java new file mode 100644 index 0000000000..72ad0e678c --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java @@ -0,0 +1,103 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ +package mage.client.deckeditor.collection.viewer; + +import mage.client.cards.BigCard; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +/** + * Pane with big card and mage book. + * + * @author nantuko + */ +public class CollectionViewerPanel extends JPanel { + public CollectionViewerPanel() { + initComponents(); + } + + public void initComponents() { + jPanel1 = new javax.swing.JPanel(); + jPanel1.setOpaque(false); + bigCard = new BigCard(); + BoxLayout boxlayout = new BoxLayout(jPanel1, BoxLayout.X_AXIS); + jPanel1.setLayout(boxlayout); + bigCard.setAlignmentY(Component.BOTTOM_ALIGNMENT); + bigCard.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); + jPanel1.add(bigCard); + + jPanel2 = new MageBookContainer(); + jPanel2.setOpaque(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, 604, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 615, Short.MAX_VALUE) + ); + } + + private class MageBookContainer extends JPanel { + public MageBookContainer() { + super(); + initComponents(); + } + + public void initComponents() { + jPanel = new JPanel(); + jScrollPane1 = new JScrollPane(jPanel); + jScrollPane1.getViewport().setBackground(new Color(0,0,0,0)); + + jPanel.setLayout(new GridBagLayout()); // centers mage book + jPanel.setBackground(new Color(0,0,0,0)); + jPanel.add(new MageBook(bigCard)); + + setLayout(new java.awt.BorderLayout()); + add(jScrollPane1, java.awt.BorderLayout.CENTER); + } + + private JPanel jPanel; + private javax.swing.JScrollPane jScrollPane1; + } + + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private mage.client.cards.BigCard bigCard; + +} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java new file mode 100644 index 0000000000..a10e83fccf --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -0,0 +1,305 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ + +package mage.client.deckeditor.collection.viewer; + +import mage.cards.Card; +import mage.cards.CardDimensions; +import mage.cards.MageCard; +import mage.client.cards.BigCard; +import mage.client.cards.CardsStorage; +import mage.client.components.HoverButton; +import mage.client.components.ImageButton; +import mage.client.components.arcane.GlowText; +import mage.client.components.arcane.ManaSymbols; +import mage.client.plugins.impl.Plugins; +import mage.client.util.Command; +import mage.client.util.Config; +import mage.client.util.ImageHelper; +import mage.components.ImagePanel; +import mage.utils.ThreadUtils; +import mage.view.CardView; +import org.apache.log4j.Logger; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.UUID; + +/** + * Mage book with cards and page flipping. + * + * @author nantuko + */ +public class MageBook extends JComponent { + + public MageBook(BigCard bigCard) { + super(); + this.bigCard = bigCard; + initComponents(); + } + + private void initComponents() { + setOpaque(false); + setSize(WIDTH, HEIGHT); + setPreferredSize(new Dimension(WIDTH, HEIGHT)); + setMinimumSize(new Dimension(WIDTH, HEIGHT)); + //setBorder(BorderFactory.createLineBorder(Color.green)); + + jPanelLeft = getImagePanel(LEFT_PANEL_IMAGE_PATH, ImagePanel.TILED); + jPanelLeft.setPreferredSize(new Dimension(LEFT_RIGHT_PAGES_WIDTH, 0)); + jPanelLeft.setLayout(null); + jPanelCenter = getImagePanel(CENTER_PANEL_IMAGE_PATH, ImagePanel.SCALED); + jPanelCenter.setLayout(new BorderLayout()); + jPanelRight = getImagePanel(RIGHT_PANEL_IMAGE_PATH, ImagePanel.TILED); + jPanelRight.setPreferredSize(new Dimension(LEFT_RIGHT_PAGES_WIDTH, 0)); + jPanelRight.setLayout(null); + + jLayeredPane = new JLayeredPane(); + jPanelCenter.add(jLayeredPane, BorderLayout.CENTER); + + Image image = ImageHelper.loadImage(LEFT_PAGE_BUTTON_IMAGE_PATH); + pageLeft = new HoverButton(null, image, image, image, new Rectangle(64,64)); + pageLeft.setBounds(0,0,64,64); + pageLeft.setVisible(false); + pageLeft.setObserver(new Command() { + public void execute() { + currentPage--; + if (currentPage == 0) { + pageLeft.setVisible(false); + } + pageRight.setVisible(true); + showCards(); + } + }); + + image = ImageHelper.loadImage(RIGHT_PAGE_BUTTON_IMAGE_PATH); + pageRight = new HoverButton(null, image, image, image, new Rectangle(64,64)); + pageRight.setBounds(WIDTH - 2*LEFT_RIGHT_PAGES_WIDTH - 64,0,64,64); + pageRight.setVisible(false); + pageRight.setObserver(new Command() { + public void execute() { + currentPage++; + pageLeft.setVisible(true); + pageRight.setVisible(false); + showCards(); + } + }); + + addSetTabs(); + + setLayout(new BorderLayout()); + add(jPanelLeft, BorderLayout.LINE_START); + add(jPanelCenter, BorderLayout.CENTER); + add(jPanelRight, BorderLayout.LINE_END); + + cardDimensions = new CardDimensions(0.45d); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showCards(); + } + }); + } + + private void addLeftRightPageButtons() { + jLayeredPane.add(pageLeft, JLayeredPane.DEFAULT_LAYER, 0); + jLayeredPane.add(pageRight, JLayeredPane.DEFAULT_LAYER, 1); + } + + private void addSetTabs() { + jPanelLeft.removeAll(); + jPanelRight.removeAll(); + Image image = ImageHelper.loadImage(LEFT_TAB_IMAGE_PATH); + Image imageRight = ImageHelper.loadImage(RIGHT_TAB_IMAGE_PATH); + int y = 0; + int dy = 0; + if (CardsStorage.getSetCodes().size() > 1) { + dy = (HEIGHT - 120) / (CardsStorage.getSetCodes().size() - 1) + 1; + } + int count = 0; + JPanel currentPanel = jPanelLeft; + for (String set : CardsStorage.getSetCodes()) { + HoverButton tab = new HoverButton(null, image, image, image, new Rectangle(39,120)); + Image setImage = ManaSymbols.getSetSymbolImage(set); + if (setImage != null) { + tab.setOverlayImage(setImage); + } else { + System.out.println("Couldn't find: " + "/plugins/images/sets/" + set + ".jpg"); + } + tab.setBounds(0, y, 39, 120); + final String _set = set; + tab.setObserver(new Command() { + public void execute() { + currentPage = 0; + currentSet = _set; + pageLeft.setVisible(false); + pageRight.setVisible(false); + addSetTabs(); + showCards(); + } + }); + currentPanel.add(tab, JLayeredPane.DEFAULT_LAYER + count++, 0); + y += dy; + if (set.equals(currentSet)) { + currentPanel = jPanelRight; + image = imageRight; + } + } + jPanelLeft.revalidate(); + jPanelLeft.repaint(); + jPanelRight.revalidate(); + jPanelRight.repaint(); + } + + private void showCards() { + jLayeredPane.removeAll(); + addLeftRightPageButtons(); + + java.util.List<Card> cards = getCards(currentPage, currentSet); + int size = cards.size(); + + Rectangle rectangle = new Rectangle(); + rectangle.translate(OFFSET_X, OFFSET_Y); + for (int i = 0; i < Math.min(CARDS_PER_PAGE / 2, size); i++) { + addCard(new CardView(cards.get(i)), bigCard, null, rectangle); + rectangle = CardPosition.translatePosition(i, rectangle); + } + + // calculate the x offset of the second (right) page + int second_page_x = (WIDTH - 2*LEFT_RIGHT_PAGES_WIDTH) - + (cardDimensions.frameWidth+ CardPosition.GAP_X)*3 + CardPosition.GAP_X - OFFSET_X; + + rectangle.setLocation(second_page_x, OFFSET_Y); + for (int i = CARDS_PER_PAGE / 2; i < Math.min(CARDS_PER_PAGE, size); i++) { + addCard(new CardView(cards.get(i)), bigCard, null, rectangle); + rectangle = CardPosition.translatePosition(i - CARDS_PER_PAGE / 2, rectangle); + } + } + + private void addCard(CardView card, BigCard bigCard, UUID gameId, Rectangle rectangle) { + final MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, cardDimensions, gameId, false); + cardImg.setBounds(rectangle); + jLayeredPane.add(cardImg, JLayeredPane.DEFAULT_LAYER, 10); + cardImg.update(card); + cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight); + + GlowText label = new GlowText(); + label.setGlow(Color.green, 12, 0.0f); + label.setText("Implemented"); + label.setBounds(rectangle.x + 15, rectangle.y + cardDimensions.frameHeight + 7, 100, 30); + jLayeredPane.add(label); + } + + private java.util.List<Card> getCards(int page, String set) { + int start = page * CARDS_PER_PAGE; + int end = (page + 1) * CARDS_PER_PAGE; + java.util.List<Card> cards = CardsStorage.getAllCards(start, end, currentSet); + if (cards.size() > CARDS_PER_PAGE) { + pageRight.setVisible(true); + } + return cards; + } + + private ImagePanel getImagePanel(String filename, int type) { + try { + InputStream is = this.getClass().getResourceAsStream(filename); + + if (is == null) { + throw new FileNotFoundException("Couldn't find " + filename + " in resources."); + } + + BufferedImage background = ImageIO.read(is); + + if (background == null) { + throw new FileNotFoundException("Couldn't find " + filename + " in resources."); + } + + return new ImagePanel(background, type); + + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * Defines the position of the next card on the mage book + */ + private static class CardPosition { + private CardPosition() { + } + + public static Rectangle translatePosition(int index, Rectangle r) { + Rectangle rect = new Rectangle(r); + rect.translate((cardDimensions.frameWidth+GAP_X) * dx[index], + (cardDimensions.frameHeight + GAP_Y) * dy[index]); + return rect; + } + + private static final int[] dx = {1, 1, -2, 1, 1, -2, 1, 1, 2, 1, -2, 1, 1, -2, 1, 1}; + private static final int[] dy = {0, 0, 1, 0, 0, 1, 0, 0, -2, 0, 1, 0, 0, 1, 0, 0}; + public static final int GAP_X = 17; + public static final int GAP_Y = 45; + private static int cardWidth; + private static int cardHeight; + } + + private JPanel jPanelLeft; + private ImagePanel jPanelCenter; + private JPanel jPanelRight; + private JLayeredPane jLayeredPane; + private BigCard bigCard; + private HoverButton pageLeft; + private HoverButton pageRight; + + private int currentPage = 0; + private String currentSet = "M10"; + + private static CardDimensions cardDimensions = new CardDimensions(1.2d); + private static Font font = new Font("Arial", Font.PLAIN, 14); + private static final Logger log = Logger.getLogger(MageBook.class); + + static private final String CENTER_PANEL_IMAGE_PATH = "/book_bg.jpg"; + static private final String RIGHT_PANEL_IMAGE_PATH = "/book_right.jpg"; + static private final String LEFT_PANEL_IMAGE_PATH = "/book_left.jpg"; + static private final String LEFT_PAGE_BUTTON_IMAGE_PATH = "/book_pager_left.png"; + static private final String RIGHT_PAGE_BUTTON_IMAGE_PATH = "/book_pager_right.png"; + static private final String LEFT_TAB_IMAGE_PATH = "/tab_left.png"; + static private final String RIGHT_TAB_IMAGE_PATH = "/tab_right.png"; + static private final int CARDS_PER_PAGE = 18; + static private final int WIDTH = 950; + static private final int HEIGHT = 650; + static private final int OFFSET_X = 25; + static private final int OFFSET_Y = 20; + static private final int LEFT_RIGHT_PAGES_WIDTH = 40; +} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/TestMageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/TestMageBook.java new file mode 100644 index 0000000000..2add19017e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/TestMageBook.java @@ -0,0 +1,21 @@ +package mage.client.deckeditor.collection.viewer; + +import mage.client.components.arcane.ManaSymbols; +import mage.client.plugins.impl.Plugins; + +import javax.swing.*; + +/** + * @author nantuko + */ +public class TestMageBook extends JFrame { + public static void main(String[] args) { + Plugins.getInstance().loadPlugins(); + ManaSymbols.loadImages(); + JFrame frame = new TestMageBook(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(new MageBook(null)); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java index 9a0d4fd06b..385ba9dc92 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java @@ -100,7 +100,7 @@ public class ShowCardsDialog extends MageDialog implements MouseListener { tmp.setAbility(card); // cross-reference, required for ability picker card = tmp; } - MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, dimension, gameId); + MageCard cardImg = Plugins.getInstance().getMageCard(card, bigCard, dimension, gameId, true); cardImg.setBounds(rectangle); cardArea.add(cardImg); cardArea.moveToFront(cardImg); diff --git a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java index 349affb8d6..d892b9b29b 100644 --- a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java @@ -156,7 +156,7 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { } private void addPermanent(PermanentView permanent, final int count) { - final MagePermanent perm = Plugins.getInstance().getMagePermanent(permanent, bigCard, Config.dimensions, gameId); + final MagePermanent perm = Plugins.getInstance().getMagePermanent(permanent, bigCard, Config.dimensions, gameId, true); if (!Plugins.getInstance().isCardPluginLoaded()) { perm.setBounds(findEmptySpace(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight))); } else { diff --git a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java index e2fb11d671..7318768608 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java @@ -21,8 +21,8 @@ public interface MagePlugins { void shutdown(); void updateGamePanel(Map<String, JComponent> ui); JComponent updateTablePanel(Map<String, JComponent> ui); - MagePermanent getMagePermanent(PermanentView card, BigCard bigCard, CardDimensions dimension, UUID gameId); - MageCard getMageCard(CardView card, BigCard bigCard, CardDimensions dimension, UUID gameId); + MagePermanent getMagePermanent(PermanentView card, BigCard bigCard, CardDimensions dimension, UUID gameId, boolean canBeFoil); + MageCard getMageCard(CardView card, BigCard bigCard, CardDimensions dimension, UUID gameId, boolean canBeFoil); boolean isThemePluginLoaded(); boolean isCardPluginLoaded(); boolean isCounterPluginLoaded(); diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index 3562a45824..861c4129cc 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -142,6 +142,9 @@ public class MageActionCallback implements ActionCallback { } try { + if (session == null) { + return; + } final Component popupContainer = session.getUI().getComponent(MageComponents.POPUP_CONTAINER); Component popup2 = session.getUI().getComponent(MageComponents.CARD_INFO_PANE); ((CardInfoPane) popup2).setCard(data.card); @@ -211,6 +214,9 @@ public class MageActionCallback implements ActionCallback { jPopupMenu.setVisible(false); } try { + if (session == null) { + return; + } Component popupContainer = session.getUI().getComponent(MageComponents.POPUP_CONTAINER); popupContainer.setVisible(false); } catch (Exception e2) { diff --git a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java index 8b999ea4a1..b8e4869957 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java @@ -80,22 +80,22 @@ public class Plugins implements MagePlugins { } @Override - public MagePermanent getMagePermanent(PermanentView card, BigCard bigCard, CardDimensions dimension, UUID gameId) { + public MagePermanent getMagePermanent(PermanentView card, BigCard bigCard, CardDimensions dimension, UUID gameId, boolean canBeFoil) { if (cardPlugin != null) { mageActionCallback.refreshSession(); mageActionCallback.setCardPreviewComponent(bigCard); - return cardPlugin.getMagePermanent(card, dimension, gameId, mageActionCallback); + return cardPlugin.getMagePermanent(card, dimension, gameId, mageActionCallback, canBeFoil); } else { return new Permanent(card, bigCard, Config.dimensions, gameId); } } @Override - public MageCard getMageCard(CardView card, BigCard bigCard, CardDimensions dimension, UUID gameId) { + public MageCard getMageCard(CardView card, BigCard bigCard, CardDimensions dimension, UUID gameId, boolean canBeFoil) { if (cardPlugin != null) { mageActionCallback.refreshSession(); mageActionCallback.setCardPreviewComponent(bigCard); - return cardPlugin.getMageCard(card, dimension, gameId, mageActionCallback); + return cardPlugin.getMageCard(card, dimension, gameId, mageActionCallback, canBeFoil); } else { return new Card(card, bigCard, Config.dimensions, gameId); } diff --git a/Mage.Client/src/main/java/mage/client/util/Command.java b/Mage.Client/src/main/java/mage/client/util/Command.java new file mode 100644 index 0000000000..ce62caaa7a --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/Command.java @@ -0,0 +1,8 @@ +package mage.client.util; + +/** + * @author nantuko + */ +public interface Command { + public void execute(); +} diff --git a/Mage.Client/src/main/resources/book_bg.jpg b/Mage.Client/src/main/resources/book_bg.jpg new file mode 100644 index 0000000000..5edc4cccc9 Binary files /dev/null and b/Mage.Client/src/main/resources/book_bg.jpg differ diff --git a/Mage.Client/src/main/resources/book_left.jpg b/Mage.Client/src/main/resources/book_left.jpg new file mode 100644 index 0000000000..84bb854566 Binary files /dev/null and b/Mage.Client/src/main/resources/book_left.jpg differ diff --git a/Mage.Client/src/main/resources/book_pager_left.png b/Mage.Client/src/main/resources/book_pager_left.png new file mode 100644 index 0000000000..c1e1e1550f Binary files /dev/null and b/Mage.Client/src/main/resources/book_pager_left.png differ diff --git a/Mage.Client/src/main/resources/book_pager_right.png b/Mage.Client/src/main/resources/book_pager_right.png new file mode 100644 index 0000000000..b6b06212e3 Binary files /dev/null and b/Mage.Client/src/main/resources/book_pager_right.png differ diff --git a/Mage.Client/src/main/resources/book_right.jpg b/Mage.Client/src/main/resources/book_right.jpg new file mode 100644 index 0000000000..fe48ea2f78 Binary files /dev/null and b/Mage.Client/src/main/resources/book_right.jpg differ diff --git a/Mage.Client/src/main/resources/tab_left.png b/Mage.Client/src/main/resources/tab_left.png new file mode 100644 index 0000000000..b3ba91fc86 Binary files /dev/null and b/Mage.Client/src/main/resources/tab_left.png differ diff --git a/Mage.Client/src/main/resources/tab_right.png b/Mage.Client/src/main/resources/tab_right.png new file mode 100644 index 0000000000..569138b883 Binary files /dev/null and b/Mage.Client/src/main/resources/tab_right.png differ diff --git a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java index 7d8bf3b659..05818cd70c 100644 --- a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java +++ b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java @@ -25,8 +25,8 @@ import net.xeoh.plugins.base.Plugin; * @author nantuko */ public interface CardPlugin extends Plugin { - MagePermanent getMagePermanent(PermanentView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback); - MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback); + MagePermanent getMagePermanent(PermanentView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback, boolean canBeFoil); + MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback, boolean canBeFoil); void sortPermanents(Map<String, JComponent> ui, Collection<MagePermanent> cards); void downloadImages(Set<Card> allCards); void downloadSymbols(); diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java index 9500ed5826..283221690f 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -1,23 +1,9 @@ package org.mage.plugins.card; -import java.awt.BorderLayout; -import java.awt.Frame; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.*; - -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JLayeredPane; -import javax.swing.JScrollPane; - import mage.cards.Card; import mage.cards.CardDimensions; import mage.cards.MagePermanent; import mage.cards.action.ActionCallback; -import mage.components.CardInfoPane; import mage.interfaces.plugin.CardPlugin; import mage.utils.CardUtil; import mage.view.CardView; @@ -26,7 +12,6 @@ import net.xeoh.plugins.base.annotations.PluginImplementation; import net.xeoh.plugins.base.annotations.events.Init; import net.xeoh.plugins.base.annotations.events.PluginLoaded; import net.xeoh.plugins.base.annotations.meta.Author; - import org.apache.log4j.Logger; import org.mage.card.arcane.Animation; import org.mage.card.arcane.CardPanel; @@ -40,436 +25,440 @@ import org.mage.plugins.card.dl.sources.GathererSymbols; import org.mage.plugins.card.images.DownloadPictures; import org.mage.plugins.card.info.CardInfoPaneImpl; +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.*; +import java.util.List; + /** * {@link CardPlugin} implementation. * - * @version 0.4 05.01.2011 Added support for foil cards. - * @version 0.3 07.11.2010 Mage cards. - * @version 0.2 07.11.2010 Downloading images. - * @version 0.1 01.11.2010 Mage permanents. Sorting card layout. * @author nantuko + * @version 0.1 01.11.2010 Mage permanents. Sorting card layout. */ @PluginImplementation @Author(name = "nantuko") public class CardPluginImpl implements CardPlugin { - private final static Logger log = Logger.getLogger(CardPluginImpl.class); + private final static Logger log = Logger.getLogger(CardPluginImpl.class); - static private final int GUTTER_Y = 15; - static private final int GUTTER_X = 5; - static final float EXTRA_CARD_SPACING_X = 0.04f; - static private final float CARD_SPACING_Y = 0.03f; - static private final float STACK_SPACING_X = 0.07f; - static private final float STACK_SPACING_Y = 0.13f; - static private final int MW_GUIDE_HEIGHT = 30; + static private final int GUTTER_Y = 15; + static private final int GUTTER_X = 5; + static final float EXTRA_CARD_SPACING_X = 0.04f; + static private final float CARD_SPACING_Y = 0.03f; + static private final float STACK_SPACING_X = 0.07f; + static private final float STACK_SPACING_Y = 0.13f; + static private final int MW_GUIDE_HEIGHT = 30; - private int landStackMax = 5; - private int cardWidthMin = 50, cardWidthMax = Constants.CARD_SIZE_FULL.width; - private boolean stackVertical = false; + private int landStackMax = 5; + private int cardWidthMin = 50, cardWidthMax = Constants.CARD_SIZE_FULL.width; + private boolean stackVertical = false; - private int playAreaWidth, playAreaHeight; - private int cardWidth, cardHeight; - private int extraCardSpacingX, cardSpacingX, cardSpacingY; - private int stackSpacingX, stackSpacingY; - private List<Row> rows = new ArrayList<Row>(); + private int playAreaWidth, playAreaHeight; + private int cardWidth, cardHeight; + private int extraCardSpacingX, cardSpacingX, cardSpacingY; + private int stackSpacingX, stackSpacingY; + private List<Row> rows = new ArrayList<Row>(); - @Init - public void init() { - } + @Init + public void init() { + } - @PluginLoaded - public void newPlugin(CardPlugin plugin) { - ManaSymbols.loadImages(); - log.info(plugin.toString() + " has been loaded."); - } + @PluginLoaded + public void newPlugin(CardPlugin plugin) { + ManaSymbols.loadImages(); + log.info(plugin.toString() + " has been loaded."); + } - public String toString() { - return "[Card plugin, version 0.4]"; - } + public String toString() { + return "[Card plugin, version 0.4]"; + } - @Override - public MagePermanent getMagePermanent(PermanentView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback) { - boolean foil = (new Random()).nextInt(5) == 0; - CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback, foil); - cardPanel.setShowCastingCost(true); - cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); - cardPanel.setShowCastingCost(true); - return cardPanel; - } - - @Override - public MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback) { - boolean foil = (new Random()).nextInt(5) == 0; + @Override + public MagePermanent getMagePermanent(PermanentView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback, boolean canBeFoil) { + boolean foil = canBeFoil && (new Random()).nextInt(5) == 0; CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback, foil); - cardPanel.setShowCastingCost(true); - cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); - cardPanel.setShowCastingCost(true); + cardPanel.setShowCastingCost(true); + cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); + cardPanel.setShowCastingCost(true); + return cardPanel; + } - return cardPanel; - } + @Override + public MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback, boolean canBeFoil) { + boolean foil = canBeFoil && (new Random()).nextInt(5) == 0; + CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback, foil); + cardPanel.setShowCastingCost(true); + cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); + cardPanel.setShowCastingCost(true); - @Override - public void sortPermanents(Map<String, JComponent> ui, Collection<MagePermanent> permanents) { - if (ui == null) - throw new RuntimeException("Error: no components"); - JComponent component = ui.get("jScrollPane"); - JComponent component2 = ui.get("battlefieldPanel"); - if (component == null) - throw new RuntimeException("Error: jScrollPane is missing"); - if (component2 == null) - throw new RuntimeException("Error: battlefieldPanel is missing"); - if (!(component instanceof JScrollPane)) - throw new RuntimeException("Error: jScrollPane has wrong type."); - if (!(component instanceof JScrollPane)) - throw new RuntimeException("Error: battlefieldPanel is missing"); - - JScrollPane jScrollPane = (JScrollPane)component; - JLayeredPane battlefieldPanel = (JLayeredPane)component2; - - Row allLands = new Row(); + return cardPanel; + } - outerLoop: // - for (MagePermanent permanent : permanents) { - if (!CardUtil.isLand(permanent) || CardUtil.isCreature(permanent)) - continue; + @Override + public void sortPermanents(Map<String, JComponent> ui, Collection<MagePermanent> permanents) { + if (ui == null) + throw new RuntimeException("Error: no components"); + JComponent component = ui.get("jScrollPane"); + JComponent component2 = ui.get("battlefieldPanel"); + if (component == null) + throw new RuntimeException("Error: jScrollPane is missing"); + if (component2 == null) + throw new RuntimeException("Error: battlefieldPanel is missing"); + if (!(component instanceof JScrollPane)) + throw new RuntimeException("Error: jScrollPane has wrong type."); + if (!(component instanceof JScrollPane)) + throw new RuntimeException("Error: battlefieldPanel is missing"); - int insertIndex = -1; + JScrollPane jScrollPane = (JScrollPane) component; + JLayeredPane battlefieldPanel = (JLayeredPane) component2; - // Find lands with the same name. - for (int i = 0, n = allLands.size(); i < n; i++) { - Stack stack = allLands.get(i); - MagePermanent firstPanel = stack.get(0); - if (firstPanel.getOriginal().getName().equals(permanent.getOriginal().getName())) { - if (!empty(firstPanel.getLinks())) { - // Put this land to the left of lands with the same name and attachments. - insertIndex = i; - break; - } - if (!empty(permanent.getLinks()) || stack.size() == landStackMax) { - // If this land has attachments or the stack is full, put it to the right. - insertIndex = i + 1; - continue; - } - // Add to stack. - stack.add(0, permanent); - continue outerLoop; - } - if (insertIndex != -1) - break; - } + Row allLands = new Row(); - Stack stack = new Stack(); - stack.add(permanent); - allLands.add(insertIndex == -1 ? allLands.size() : insertIndex, stack); - } + outerLoop: + // + for (MagePermanent permanent : permanents) { + if (!CardUtil.isLand(permanent) || CardUtil.isCreature(permanent)) + continue; - Row allCreatures = new Row(permanents, RowType.creature); - Row allOthers = new Row(permanents, RowType.other); + int insertIndex = -1; - cardWidth = cardWidthMax; - Rectangle rect = jScrollPane.getVisibleRect(); - playAreaWidth = rect.width; - playAreaHeight = rect.height - MW_GUIDE_HEIGHT; - while (true) { - rows.clear(); - cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO); - extraCardSpacingX = (int) Math.round(cardWidth * EXTRA_CARD_SPACING_X); - cardSpacingX = cardHeight - cardWidth + extraCardSpacingX; - cardSpacingY = (int) Math.round(cardHeight * CARD_SPACING_Y); - stackSpacingX = stackVertical ? 0 : (int) Math.round(cardWidth * STACK_SPACING_X); - stackSpacingY = (int) Math.round(cardHeight * STACK_SPACING_Y); - Row creatures = (Row) allCreatures.clone(); - Row lands = (Row) allLands.clone(); - Row others = (Row) allOthers.clone(); - // Wrap all creatures and lands. - wrap(creatures, rows, -1); - int afterCreaturesIndex = rows.size(); - wrap(lands, rows, afterCreaturesIndex); - // Store the current rows and others. - List<Row> storedRows = new ArrayList<Row>(rows.size()); - for (Row row : rows) - storedRows.add((Row) row.clone()); - Row storedOthers = (Row) others.clone(); - // Fill in all rows with others. - for (Row row : rows) - fillRow(others, rows, row); + // Find lands with the same name. + for (int i = 0, n = allLands.size(); i < n; i++) { + Stack stack = allLands.get(i); + MagePermanent firstPanel = stack.get(0); + if (firstPanel.getOriginal().getName().equals(permanent.getOriginal().getName())) { + if (!empty(firstPanel.getLinks())) { + // Put this land to the left of lands with the same name and attachments. + insertIndex = i; + break; + } + if (!empty(permanent.getLinks()) || stack.size() == landStackMax) { + // If this land has attachments or the stack is full, put it to the right. + insertIndex = i + 1; + continue; + } + // Add to stack. + stack.add(0, permanent); + continue outerLoop; + } + if (insertIndex != -1) + break; + } - // Stop if everything fits, otherwise revert back to the stored values. - if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty()) - break; - rows = storedRows; - others = storedOthers; - // Try to put others on their own row(s) and fill in the rest. - wrap(others, rows, afterCreaturesIndex); - for (Row row : rows) - fillRow(others, rows, row); - // If that still doesn't fit, scale down. - if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty()) - break; - //cardWidth = (int)(cardWidth / 1.2); - cardWidth--; - } + Stack stack = new Stack(); + stack.add(permanent); + allLands.add(insertIndex == -1 ? allLands.size() : insertIndex, stack); + } - // Get size of all the rows. - int x, y = GUTTER_Y; - int maxRowWidth = 0; - for (Row row : rows) { - int rowBottom = 0; - x = GUTTER_X; - for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) { - Stack stack = row.get(stackIndex); - rowBottom = Math.max(rowBottom, y + stack.getHeight()); - x += stack.getWidth(); - } - y = rowBottom; - maxRowWidth = Math.max(maxRowWidth, x); - } - //setPreferredSize(new Dimension(maxRowWidth - cardSpacingX, y - cardSpacingY)); - //revalidate(); + Row allCreatures = new Row(permanents, RowType.creature); + Row allOthers = new Row(permanents, RowType.other); - // Position all card panels. - x = 0; - y = GUTTER_Y; - for (Row row : rows) { - int rowBottom = 0; - x = GUTTER_X; - for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) { - Stack stack = row.get(stackIndex); - // Align others to the right. - if (RowType.other.isType(stack.get(0))) { - x = playAreaWidth - GUTTER_X + extraCardSpacingX; - for (int i = stackIndex, n = row.size(); i < n; i++) - x -= row.get(i).getWidth(); - } - for (int panelIndex = 0, panelCount = stack.size(); panelIndex < panelCount; panelIndex++) { - MagePermanent panel = stack.get(panelIndex); - int stackPosition = panelCount - panelIndex - 1; - ///setComponentZOrder((Component)panel, panelIndex); - int panelX = x + (stackPosition * stackSpacingX); - int panelY = y + (stackPosition * stackSpacingY); - //panel.setLocation(panelX, panelY); - battlefieldPanel.moveToBack(panel); - panel.setCardBounds(panelX, panelY, cardWidth, cardHeight); - } - rowBottom = Math.max(rowBottom, y + stack.getHeight()); - x += stack.getWidth(); - } - y = rowBottom; - } - } - - private boolean empty(List<?> list) { - return list == null || list.size() == 0; - } - - private int wrap(Row sourceRow, List<Row> rows, int insertIndex) { - // The cards are sure to fit (with vertical scrolling) at the minimum card width. - boolean allowHeightOverflow = cardWidth == cardWidthMin; + cardWidth = cardWidthMax; + Rectangle rect = jScrollPane.getVisibleRect(); + playAreaWidth = rect.width; + playAreaHeight = rect.height - MW_GUIDE_HEIGHT; + while (true) { + rows.clear(); + cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO); + extraCardSpacingX = (int) Math.round(cardWidth * EXTRA_CARD_SPACING_X); + cardSpacingX = cardHeight - cardWidth + extraCardSpacingX; + cardSpacingY = (int) Math.round(cardHeight * CARD_SPACING_Y); + stackSpacingX = stackVertical ? 0 : (int) Math.round(cardWidth * STACK_SPACING_X); + stackSpacingY = (int) Math.round(cardHeight * STACK_SPACING_Y); + Row creatures = (Row) allCreatures.clone(); + Row lands = (Row) allLands.clone(); + Row others = (Row) allOthers.clone(); + // Wrap all creatures and lands. + wrap(creatures, rows, -1); + int afterCreaturesIndex = rows.size(); + wrap(lands, rows, afterCreaturesIndex); + // Store the current rows and others. + List<Row> storedRows = new ArrayList<Row>(rows.size()); + for (Row row : rows) + storedRows.add((Row) row.clone()); + Row storedOthers = (Row) others.clone(); + // Fill in all rows with others. + for (Row row : rows) + fillRow(others, rows, row); - Row currentRow = new Row(); - for (int i = 0, n = sourceRow.size() - 1; i <= n; i++) { - Stack stack = sourceRow.get(i); - // If the row is not empty and this stack doesn't fit, add the row. - int rowWidth = currentRow.getWidth(); - if (!currentRow.isEmpty() && rowWidth + stack.getWidth() > playAreaWidth) { - // Stop processing if the row is too wide or tall. - if (!allowHeightOverflow && rowWidth > playAreaWidth) - break; - if (!allowHeightOverflow && getRowsHeight(rows) + sourceRow.getHeight() > playAreaHeight) - break; - rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow); - currentRow = new Row(); - } - currentRow.add(stack); - } - // Add the last row if it is not empty and it fits. - if (!currentRow.isEmpty()) { - int rowWidth = currentRow.getWidth(); - if (allowHeightOverflow || rowWidth <= playAreaWidth) { - if (allowHeightOverflow || getRowsHeight(rows) + sourceRow.getHeight() <= playAreaHeight) { - rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow); - } - } - } - // Remove the wrapped stacks from the source row. - for (Row row : rows) - for (Stack stack : row) - sourceRow.remove(stack); - return insertIndex; - } + // Stop if everything fits, otherwise revert back to the stored values. + if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty()) + break; + rows = storedRows; + others = storedOthers; + // Try to put others on their own row(s) and fill in the rest. + wrap(others, rows, afterCreaturesIndex); + for (Row row : rows) + fillRow(others, rows, row); + // If that still doesn't fit, scale down. + if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty()) + break; + //cardWidth = (int)(cardWidth / 1.2); + cardWidth--; + } - private void fillRow(Row sourceRow, List<Row> rows, Row row) { - int rowWidth = row.getWidth(); - while (!sourceRow.isEmpty()) { - Stack stack = sourceRow.get(0); - rowWidth += stack.getWidth(); - if (rowWidth > playAreaWidth) - break; - if (stack.getHeight() > row.getHeight()) { - if (getRowsHeight(rows) - row.getHeight() + stack.getHeight() > playAreaHeight) - break; - } - row.add(sourceRow.remove(0)); - } - } + // Get size of all the rows. + int x, y = GUTTER_Y; + int maxRowWidth = 0; + for (Row row : rows) { + int rowBottom = 0; + x = GUTTER_X; + for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) { + Stack stack = row.get(stackIndex); + rowBottom = Math.max(rowBottom, y + stack.getHeight()); + x += stack.getWidth(); + } + y = rowBottom; + maxRowWidth = Math.max(maxRowWidth, x); + } + //setPreferredSize(new Dimension(maxRowWidth - cardSpacingX, y - cardSpacingY)); + //revalidate(); - private int getRowsHeight(List<Row> rows) { - int height = 0; - for (Row row : rows) - height += row.getHeight(); - return height - cardSpacingY + GUTTER_Y * 2; - } + // Position all card panels. + x = 0; + y = GUTTER_Y; + for (Row row : rows) { + int rowBottom = 0; + x = GUTTER_X; + for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) { + Stack stack = row.get(stackIndex); + // Align others to the right. + if (RowType.other.isType(stack.get(0))) { + x = playAreaWidth - GUTTER_X + extraCardSpacingX; + for (int i = stackIndex, n = row.size(); i < n; i++) + x -= row.get(i).getWidth(); + } + for (int panelIndex = 0, panelCount = stack.size(); panelIndex < panelCount; panelIndex++) { + MagePermanent panel = stack.get(panelIndex); + int stackPosition = panelCount - panelIndex - 1; + ///setComponentZOrder((Component)panel, panelIndex); + int panelX = x + (stackPosition * stackSpacingX); + int panelY = y + (stackPosition * stackSpacingY); + //panel.setLocation(panelX, panelY); + battlefieldPanel.moveToBack(panel); + panel.setCardBounds(panelX, panelY, cardWidth, cardHeight); + } + rowBottom = Math.max(rowBottom, y + stack.getHeight()); + x += stack.getWidth(); + } + y = rowBottom; + } + } - static private enum RowType { - land, creature, other; + private boolean empty(List<?> list) { + return list == null || list.size() == 0; + } - public boolean isType(MagePermanent card) { - switch (this) { - case land: - return CardUtil.isLand(card); - case creature: - return CardUtil.isCreature(card); - case other: - return !CardUtil.isLand(card) && !CardUtil.isCreature(card); - default: - throw new RuntimeException("Unhandled type: " + this); - } - } - } + private int wrap(Row sourceRow, List<Row> rows, int insertIndex) { + // The cards are sure to fit (with vertical scrolling) at the minimum card width. + boolean allowHeightOverflow = cardWidth == cardWidthMin; - private class Row extends ArrayList<Stack> { - public Row() { - super(16); - } + Row currentRow = new Row(); + for (int i = 0, n = sourceRow.size() - 1; i <= n; i++) { + Stack stack = sourceRow.get(i); + // If the row is not empty and this stack doesn't fit, add the row. + int rowWidth = currentRow.getWidth(); + if (!currentRow.isEmpty() && rowWidth + stack.getWidth() > playAreaWidth) { + // Stop processing if the row is too wide or tall. + if (!allowHeightOverflow && rowWidth > playAreaWidth) + break; + if (!allowHeightOverflow && getRowsHeight(rows) + sourceRow.getHeight() > playAreaHeight) + break; + rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow); + currentRow = new Row(); + } + currentRow.add(stack); + } + // Add the last row if it is not empty and it fits. + if (!currentRow.isEmpty()) { + int rowWidth = currentRow.getWidth(); + if (allowHeightOverflow || rowWidth <= playAreaWidth) { + if (allowHeightOverflow || getRowsHeight(rows) + sourceRow.getHeight() <= playAreaHeight) { + rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow); + } + } + } + // Remove the wrapped stacks from the source row. + for (Row row : rows) + for (Stack stack : row) + sourceRow.remove(stack); + return insertIndex; + } - public Row(Collection<MagePermanent> permanents, RowType type) { - this(); - addAll(permanents, type); - } + private void fillRow(Row sourceRow, List<Row> rows, Row row) { + int rowWidth = row.getWidth(); + while (!sourceRow.isEmpty()) { + Stack stack = sourceRow.get(0); + rowWidth += stack.getWidth(); + if (rowWidth > playAreaWidth) + break; + if (stack.getHeight() > row.getHeight()) { + if (getRowsHeight(rows) - row.getHeight() + stack.getHeight() > playAreaHeight) + break; + } + row.add(sourceRow.remove(0)); + } + } - private void addAll(Collection<MagePermanent> permanents, RowType type) { - for (MagePermanent panel : permanents) { - if (!type.isType(panel)) - continue; - Stack stack = new Stack(); - stack.add(panel); - add(stack); - } - } + private int getRowsHeight(List<Row> rows) { + int height = 0; + for (Row row : rows) + height += row.getHeight(); + return height - cardSpacingY + GUTTER_Y * 2; + } - public boolean addAll(Collection<? extends Stack> c) { - boolean changed = super.addAll(c); - c.clear(); - return changed; - } + static private enum RowType { + land, creature, other; - private int getWidth() { - if (isEmpty()) - return 0; - int width = 0; - for (Stack stack : this) - width += stack.getWidth(); - return width + GUTTER_X * 2 - extraCardSpacingX; - } + public boolean isType(MagePermanent card) { + switch (this) { + case land: + return CardUtil.isLand(card); + case creature: + return CardUtil.isCreature(card); + case other: + return !CardUtil.isLand(card) && !CardUtil.isCreature(card); + default: + throw new RuntimeException("Unhandled type: " + this); + } + } + } - private int getHeight() { - if (isEmpty()) - return 0; - int height = 0; - for (Stack stack : this) - height = Math.max(height, stack.getHeight()); - return height; - } - } + private class Row extends ArrayList<Stack> { + public Row() { + super(16); + } - private class Stack extends ArrayList<MagePermanent> { - public Stack() { - super(8); - } + public Row(Collection<MagePermanent> permanents, RowType type) { + this(); + addAll(permanents, type); + } - public boolean add(MagePermanent panel) { - boolean appended = super.add(panel); - //for (CardPanel attachedPanel : panel.attachedPanels) - //add(attachedPanel); - return appended; - } + private void addAll(Collection<MagePermanent> permanents, RowType type) { + for (MagePermanent panel : permanents) { + if (!type.isType(panel)) + continue; + Stack stack = new Stack(); + stack.add(panel); + add(stack); + } + } - private int getWidth() { - return cardWidth + (size() - 1) * stackSpacingX + cardSpacingX; - } + public boolean addAll(Collection<? extends Stack> c) { + boolean changed = super.addAll(c); + c.clear(); + return changed; + } - private int getHeight() { - return cardHeight + (size() - 1) * stackSpacingY + cardSpacingY; - } - } + private int getWidth() { + if (isEmpty()) + return 0; + int width = 0; + for (Stack stack : this) + width += stack.getWidth(); + return width + GUTTER_X * 2 - extraCardSpacingX; + } - @Override - public void downloadImages(Set<Card> allCards) { - DownloadPictures.startDownload(null, allCards); - } - - @Override - public void downloadSymbols() { - final DownloadGui g = new DownloadGui(new Downloader()); + private int getHeight() { + if (isEmpty()) + return 0; + int height = 0; + for (Stack stack : this) + height = Math.max(height, stack.getHeight()); + return height; + } + } - Iterable<DownloadJob> it = new GathererSymbols(); - - for(DownloadJob job:it) { + private class Stack extends ArrayList<MagePermanent> { + public Stack() { + super(8); + } + + public boolean add(MagePermanent panel) { + boolean appended = super.add(panel); + //for (CardPanel attachedPanel : panel.attachedPanels) + //add(attachedPanel); + return appended; + } + + private int getWidth() { + return cardWidth + (size() - 1) * stackSpacingX + cardSpacingX; + } + + private int getHeight() { + return cardHeight + (size() - 1) * stackSpacingY + cardSpacingY; + } + } + + @Override + public void downloadImages(Set<Card> allCards) { + DownloadPictures.startDownload(null, allCards); + } + + @Override + public void downloadSymbols() { + final DownloadGui g = new DownloadGui(new Downloader()); + + Iterable<DownloadJob> it = new GathererSymbols(); + + for (DownloadJob job : it) { g.getDownloader().add(job); } - it = new GathererSets(); - for(DownloadJob job:it) { - g.getDownloader().add(job); + it = new GathererSets(); + for(DownloadJob job:it) { + g.getDownloader().add(job); + } + + JDialog d = new JDialog((Frame) null, "Download pictures", false); + d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + d.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + g.getDownloader().dispose(); + } + }); + d.setLayout(new BorderLayout()); + d.add(g); + d.pack(); + d.setVisible(true); + } + + @Override + public Image getManaSymbolImage(String symbol) { + return ManaSymbols.getManaSymbolImage(symbol); + } + + @Override + public void onAddCard(MagePermanent card, int count) { + if (card != null) { + Animation.showCard((CardPanel) card, count > 0 ? count : 1); + try { + while ((card).getAlpha() + 0.05f < 1) { + Thread.sleep(30); + } + } catch (Exception e) { + e.printStackTrace(); + } } + } - - JDialog d = new JDialog((Frame) null, "Download pictures", false); - d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - d.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - g.getDownloader().dispose(); - } - }); - d.setLayout(new BorderLayout()); - d.add(g); - d.pack(); - d.setVisible(true); - } - - @Override - public Image getManaSymbolImage(String symbol) { - return ManaSymbols.getManaSymbolImage(symbol); - } - - @Override - public void onAddCard(MagePermanent card, int count) { - if (card != null) { - Animation.showCard((CardPanel) card, count > 0 ? count : 1); - try { - while ((card).getAlpha() + 0.05f < 1) { - Thread.sleep(30); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - @Override - public void onRemoveCard(MagePermanent card, int count) { - if (card != null) { - Animation.hideCard((CardPanel) card, count > 0 ? count : 1); - try { - while ((card).getAlpha() - 0.05f > 0) { - Thread.sleep(30); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } + @Override + public void onRemoveCard(MagePermanent card, int count) { + if (card != null) { + Animation.hideCard((CardPanel) card, count > 0 ? count : 1); + try { + while ((card).getAlpha() - 0.05f > 0) { + Thread.sleep(30); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } @Override public JComponent getCardInfoPane() { diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java index d2c51658f6..469568161f 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java @@ -12,7 +12,7 @@ import static org.mage.plugins.card.dl.DownloadJob.toFile; public class GathererSets implements Iterable<DownloadJob> { private static final File outDir = new File("plugins/images/sets"); private static final String[] symbols = { "M10", "M11", "ARB", "DIS", "GPT", "RAV", "ALA", - "ZEN", "WWK", "ROE", "SOM", "10E", "CFX" }; + "ZEN", "WWK", "ROE", "SOM", "10E", "CFX", "HOP" }; @Override public Iterator<DownloadJob> iterator() {