Skip to content

Commit

Permalink
Merge pull request #4211 from SJuliez/Print_AS_Cards
Browse files Browse the repository at this point in the history
Print Alpha Strike cards
  • Loading branch information
SJuliez authored Mar 4, 2023
2 parents 1c944fd + e46c54e commit ae34e64
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 10 deletions.
13 changes: 11 additions & 2 deletions megamek/src/megamek/client/ui/dialogs/ASStatsDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import megamek.common.Entity;
import megamek.common.alphaStrike.AlphaStrikeElement;
import megamek.common.alphaStrike.AlphaStrikeHelper;
import megamek.common.alphaStrike.cardDrawer.ASCardPrinter;
import megamek.common.alphaStrike.conversion.ASConverter;

import javax.swing.*;
Expand All @@ -41,8 +42,10 @@ public class ASStatsDialog extends AbstractDialog {

private final Collection<Entity> entities;
private final JButton clipBoardButton = new JButton("Copy to Clipboard");
private final JButton printButton = new JButton("Print");
private final JScrollPane scrollPane = new JScrollPane();
private final JPanel centerPanel = new JPanel();
private ASStatsTablePanel tablePanel;
private static final String COLUMN_SEPARATOR = "\t";
private static final String INTERNAL_DELIMITER = ",";

Expand All @@ -68,7 +71,9 @@ protected Container createCenterPane() {
var optionsPanel = new UIUtil.FixedYPanel(new FlowLayout(FlowLayout.LEFT));
optionsPanel.add(Box.createVerticalStrut(25));
optionsPanel.add(clipBoardButton);
optionsPanel.add(printButton);
clipBoardButton.addActionListener(e -> copyToClipboard());
printButton.addActionListener(ev -> printCards());

scrollPane.getVerticalScrollBar().setUnitIncrement(16);

Expand All @@ -81,8 +86,8 @@ protected Container createCenterPane() {

private void setupTable() {
centerPanel.remove(scrollPane);
JPanel asPanel = new ASStatsTablePanel(getFrame()).add(entities, "Selected Units").getPanel();
scrollPane.setViewportView(asPanel);
tablePanel = new ASStatsTablePanel(getFrame()).add(entities, "Selected Units");
scrollPane.setViewportView(tablePanel.getPanel());
centerPanel.add(scrollPane);
adaptToGUIScale();
}
Expand Down Expand Up @@ -143,4 +148,8 @@ private StringBuilder dataLine(AlphaStrikeElement element) {
private void adaptToGUIScale() {
UIUtil.adjustDialog(this, UIUtil.FONT_SCALE1);
}

private void printCards() {
new ASCardPrinter(tablePanel.getElements(), getFrame()).printCards();
}
}
6 changes: 6 additions & 0 deletions megamek/src/megamek/client/ui/swing/ASStatsTablePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class ASStatsTablePanel {
private int rows;
private final List<EntityGroup> groups = new ArrayList<>();
private final JFrame frame;
private final List<AlphaStrikeElement> elements = new ArrayList<>();

/**
* Constructs a panel with a table of AlphaStrike stats for any units that are added to it.
Expand Down Expand Up @@ -95,6 +96,10 @@ public JPanel getPanel() {
return panel;
}

public List<AlphaStrikeElement> getElements() {
return elements;
}

/** Assembles the JPanel. It is empty before calling this method. */
private void constructPanel() {
addVerticalSpace();
Expand Down Expand Up @@ -123,6 +128,7 @@ private void addGrouptoPanel(EntityGroup group) {
}
}
}
elements.addAll(elementList);

// Print the elements
rows++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,8 @@ protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(cardImage, 0, 0, this);
}

public ASCard getCard() {
return card;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 - The MegaMek Team. All Rights Reserved.
* Copyright (c) 2022-2023 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MegaMek.
*
Expand All @@ -24,6 +24,7 @@
import megamek.client.ui.swing.util.UIUtil;
import megamek.common.alphaStrike.ASCardDisplayable;
import megamek.common.alphaStrike.AlphaStrikeElement;
import megamek.common.alphaStrike.cardDrawer.ASCardPrinter;
import megamek.common.annotations.Nullable;
import org.apache.logging.log4j.LogManager;

Expand All @@ -34,6 +35,7 @@
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.net.URL;
import java.util.List;

/**
* This is a JPanel that displays an AlphaStrike unit card and elements to configure the display of
Expand All @@ -45,6 +47,7 @@ public class ConfigurableASCardPanel extends JPanel {
private final JComboBox<String> fontChooser = new JComboBox<>();
private final JComboBox<Float> sizeChooser = new JComboBox<>();
private final JButton copyButton = new JButton("Copy to Clipboard");
private final JButton printButton = new JButton("Print");
private final JButton mulButton = new JButton("MUL");
private final JButton conversionButton = new JButton("Conversion Report");
private final ASCardPanel cardPanel = new ASCardPanel();
Expand Down Expand Up @@ -79,6 +82,7 @@ public ConfigurableASCardPanel(@Nullable ASCardDisplayable element, JFrame paren
sizeChooser.setRenderer((list, value, index, isSelected, cellHasFocus) -> new JLabel(Float.toString(value)));

copyButton.addActionListener(ev -> copyCardToClipboard());
printButton.addActionListener(ev -> printCard());

mulButton.addActionListener(ev -> showMUL());
mulButton.setToolTipText("Show the Master Unit List entry for this unit. Opens a browser window.");
Expand All @@ -96,6 +100,8 @@ public ConfigurableASCardPanel(@Nullable ASCardDisplayable element, JFrame paren
chooserLine.add(Box.createHorizontalStrut(15));
chooserLine.add(copyButton);
chooserLine.add(Box.createHorizontalStrut(15));
chooserLine.add(printButton);
chooserLine.add(Box.createHorizontalStrut(15));
chooserLine.add(mulButton);
chooserLine.add(Box.createHorizontalStrut(15));
chooserLine.add(conversionButton);
Expand Down Expand Up @@ -166,6 +172,10 @@ private void showConversionReport() {
}
}

private void printCard() {
new ASCardPrinter(List.of(element), parent).printCards();
}

// Taken from https://alvinalexander.com/java/java-copy-image-to-clipboard-example/
private void copyCardToClipboard() {
ImageSelection imgSel = new ImageSelection(cardPanel.getCardImage());
Expand Down
2 changes: 1 addition & 1 deletion megamek/src/megamek/client/ui/swing/util/UIUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public static void adjustContainer(Container parentCon, int fontSize) {
if ((comp instanceof JButton) || (comp instanceof JLabel)
|| (comp instanceof JComboBox<?>) || (comp instanceof JTextField) || (comp instanceof JSlider)
|| (comp instanceof JSpinner) || (comp instanceof JTextArea) || (comp instanceof JToggleButton)
|| (comp instanceof JTable) || (comp instanceof JList)
|| (comp instanceof JTable) || (comp instanceof JList) || (comp instanceof JProgressBar)
|| (comp instanceof JEditorPane) || (comp instanceof JTree)) {
if ((comp.getFont() != null) && (sf != comp.getFont().getSize())) {
comp.setFont(comp.getFont().deriveFont((float) sf));
Expand Down
7 changes: 4 additions & 3 deletions megamek/src/megamek/common/alphaStrike/cardDrawer/ASCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@
*/
public class ASCard {

protected final static int WIDTH = 1050;
protected final static int HEIGHT = 750;
public final static int WIDTH = 1050;
public final static int HEIGHT = 750;
public final static double PRINT_SCALE = 3.5 * 72 / WIDTH; // 3.5" wide, 1/72 dots per inch
protected final static int BORDER = 21;
protected final static int ARMOR_PIP_SIZE = 22;
protected final static int DAMAGE_PIP_SIZE = 18;
Expand Down Expand Up @@ -222,7 +223,7 @@ protected void initializeFonts(Font lightFont, Font boldFont, Font blackFont) {
}

/** This method controls drawing the card. */
protected final void drawCard(Graphics g) {
public final void drawCard(Graphics g) {
initializeFonts(lightFont, boldFont, blackFont);
Graphics2D g2D = (Graphics2D) g;
GUIPreferences.AntiAliasifSet(g);
Expand Down
201 changes: 201 additions & 0 deletions megamek/src/megamek/common/alphaStrike/cardDrawer/ASCardPrinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* Copyright (c) 2022-2023 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MegaMek.
*
* MegaMek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MegaMek is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MegaMek. If not, see <http://www.gnu.org/licenses/>.
*/
package megamek.common.alphaStrike.cardDrawer;

import megamek.MMConstants;
import megamek.client.ui.swing.GUIPreferences;
import megamek.client.ui.swing.util.UIUtil;
import megamek.codeUtilities.StringUtility;
import megamek.common.alphaStrike.ASCardDisplayable;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* This class prints a collection of one or more Alpha Strike cards. The cards to be printed can be created
* from either an {@link megamek.common.alphaStrike.AlphaStrikeElement} or a {@link megamek.common.MechSummary}.
* It shows a progress bar dialog but the printing happens in the background and the calling window is not blocked.
*/
public class ASCardPrinter implements Printable {

private final JFrame parent;
private final List<CardSlot> cardSlots = new ArrayList<>();
private ProgressPopup progressPopup;
private int row;
private int column;
private AffineTransform baseTransform;

// The column and row count depend on the page format of a given print job and are set anew for each print call
private int columnCount = 2;
private int rowCount = 4;

/**
* Creates a new ASCardPrinter object for the given ASCardDisplayable elements (either
* {@link megamek.common.alphaStrike.AlphaStrikeElement} or {@link megamek.common.MechSummary}.
* The parent is used for the progress dialog. Print the cards by calling {@link #printCards()}.
*/
public ASCardPrinter(Collection<? extends ASCardDisplayable> elements, JFrame parent) {
Font userSelectedFont = userSelectedFont();
this.parent = parent;
for (ASCardDisplayable element : elements) {
ASCard card = ASCard.createCard(element);
card.setFont(userSelectedFont);
cardSlots.add(new CardSlot(card, false));
if (element.usesArcs()) {
cardSlots.add(new CardSlot(card, true));
}
}
}

/**
* Starts a printing process for the carsd of this ASCardPrinter. This will display the usual printer
* selection dialog and a progress dialog. Printing itself happens in the background and the progress
* dialog can be closed.
*/
public void printCards() {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
boolean doPrint = job.printDialog();
if (doPrint) {
progressPopup = new ProgressPopup(cardSlots.size(), parent);
progressPopup.setVisible(true);
new PrintCardTask(job).execute();
}
}

private class PrintCardTask extends SwingWorker<Void, Integer> {

private final PrinterJob job;

PrintCardTask(PrinterJob job) {
this.job = job;
}

@Override
protected Void doInBackground() throws Exception {
try {
job.print();
} catch (PrinterException ex) {
JOptionPane.showMessageDialog(parent, ex.getMessage(), "ERROR", JOptionPane.ERROR_MESSAGE);
}
return null;
}

@Override
protected void done() {
progressPopup.setVisible(false);
}
}

private static class ProgressPopup extends JDialog {
private final JProgressBar progressBar = new JProgressBar();

ProgressPopup(int maximum, JFrame parent) {
super(parent, "Print Cards");
progressBar.setMaximum(maximum);
progressBar.setStringPainted(true);
progressBar.setBorder(new EmptyBorder(20, 40, 20, 40));
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
add(Box.createVerticalStrut(20));
add(new JLabel("Printing Alpha Strike Cards...", JLabel.CENTER));
add(progressBar);

UIUtil.adjustDialog(ProgressPopup.this, UIUtil.FONT_SCALE1);
setLocationRelativeTo(null);
pack();
}
}

@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
double height = 2.5 * 72;
rowCount = (int) (pageFormat.getImageableHeight() / height);
columnCount = (int) (pageFormat.getImageableWidth() / (3.5 * 72));
if (isPageIndexValid(pageIndex)) {
double fullHeight = rowCount * height;
Graphics2D g2D = (Graphics2D) graphics;
double topCardY = pageFormat.getHeight() / 2 - fullHeight / 2;
g2D.translate(pageFormat.getWidth() / 2, topCardY);
g2D.scale(ASCard.PRINT_SCALE, ASCard.PRINT_SCALE);
baseTransform = g2D.getTransform();

int elementIndex = pageStartSlotIndex(pageIndex);
while ((elementIndex < pageStartSlotIndex(pageIndex + 1)) && (elementIndex < cardSlots.size())) {
goToPrintSlot(elementIndex - pageStartSlotIndex(pageIndex), g2D);
CardSlot cardSlot = cardSlots.get(elementIndex);
if (cardSlot.flipSide) {
((ASLargeAeroCard) (cardSlot.card)).drawFlipside(g2D);
} else {
cardSlot.card.drawCard(g2D);
}
elementIndex++;
}

final int doneCards = elementIndex;
SwingUtilities.invokeLater(() ->
progressPopup.progressBar.setValue(doneCards));
return Printable.PAGE_EXISTS;
} else {
return Printable.NO_SUCH_PAGE;
}
}

private Font userSelectedFont() {
String fontName = GUIPreferences.getInstance().getAsCardFont();
return (StringUtility.isNullOrBlank(fontName)
? new Font(MMConstants.FONT_SANS_SERIF, Font.PLAIN, 14)
: Font.decode(fontName));
}

private int pageStartSlotIndex(int pageIndex) {
return columnCount * rowCount * pageIndex;
}

private boolean isPageIndexValid(int pageIndex) {
return cardSlots.size() > pageStartSlotIndex(pageIndex);
}

/** Sets the translate in the given g2D to the given card slot, going down the first column, then the second... */
private void goToPrintSlot(int slot, Graphics2D g2D) {
g2D.setTransform(baseTransform);
column = slot / rowCount;
row = slot - column * rowCount;
g2D.translate(-ASCard.WIDTH * columnCount / 2 + ASCard.WIDTH * column, ASCard.HEIGHT * row);
}

/** Holds the card for a card slot on the page together with the info if this is the front or back side. */
private static class CardSlot {
ASCard card;
boolean flipSide;

CardSlot(ASCard card, boolean flipSide) {
this.card = card;
this.flipSide = flipSide;
}
}
}
Loading

0 comments on commit ae34e64

Please sign in to comment.