Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print Alpha Strike cards #4211

Merged
merged 4 commits into from
Mar 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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