diff --git a/megameklab/data/images/widgets/moveBottom.png b/megameklab/data/images/widgets/moveBottom.png new file mode 100644 index 000000000..5c21f674f Binary files /dev/null and b/megameklab/data/images/widgets/moveBottom.png differ diff --git a/megameklab/data/images/widgets/moveDown.png b/megameklab/data/images/widgets/moveDown.png new file mode 100644 index 000000000..53d73286e Binary files /dev/null and b/megameklab/data/images/widgets/moveDown.png differ diff --git a/megameklab/data/images/widgets/moveTop.png b/megameklab/data/images/widgets/moveTop.png new file mode 100644 index 000000000..5e10d14d6 Binary files /dev/null and b/megameklab/data/images/widgets/moveTop.png differ diff --git a/megameklab/data/images/widgets/moveUp.png b/megameklab/data/images/widgets/moveUp.png new file mode 100644 index 000000000..b43309e6c Binary files /dev/null and b/megameklab/data/images/widgets/moveUp.png differ diff --git a/megameklab/src/megameklab/ui/dialog/PrintQueueDialog.java b/megameklab/src/megameklab/ui/dialog/PrintQueueDialog.java index 055eef46a..025cd9746 100644 --- a/megameklab/src/megameklab/ui/dialog/PrintQueueDialog.java +++ b/megameklab/src/megameklab/ui/dialog/PrintQueueDialog.java @@ -21,6 +21,7 @@ import megamek.client.ui.baseComponents.MMButton; import megamek.client.ui.swing.UnitLoadingDialog; import megamek.common.BTObject; +import megamek.common.Configuration; import megamek.common.Entity; import megamek.common.MechFileParser; import megameklab.printing.PageBreak; @@ -30,14 +31,18 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.border.TitledBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.IntStream; import static java.util.stream.Collectors.toList; @@ -48,12 +53,17 @@ * @author Simon (Juliez) */ public class PrintQueueDialog extends AbstractMMLButtonDialog { - private final boolean printToPdf; private final JButton addFromFileButton = new JButton("Add From File"); private final JButton addFromCacheButton = new JButton("Add From Cache"); private final JButton addPageBreakButton = new JButton("Add Page Break"); private final JButton removeButton = new JButton("Remove Selected"); + + private final JButton moveTopButton = new JButton(icon("moveTop.png")); + private final JButton moveUpButton = new JButton(icon("moveUp.png")); + private final JButton moveDownButton = new JButton(icon("moveDown.png")); + private final JButton moveBottomButton = new JButton(icon("moveBottom.png")); + private final JCheckBox oneUnitPerSheetCheck = new JCheckBox("Print each unit to a separate page"); private final JFrame parent; private final List units = new ArrayList<>(); @@ -66,6 +76,15 @@ public PrintQueueDialog(JFrame parent, boolean printToPdf) { initialize(); } + private static ImageIcon icon(String name) { + var path = Configuration.widgetsDir().toPath().resolve(name); + try { + return new ImageIcon(path.toUri().toURL()); + } catch (MalformedURLException e) { + return null; + } + } + @Override protected Container createCenterPane() { addFromCacheButton.addActionListener(e -> selectFromCache()); @@ -77,11 +96,25 @@ protected Container createCenterPane() { removeButton.addActionListener(e -> removeSelectedUnits()); removeButton.setEnabled(false); removeButton.setMnemonic(KeyEvent.VK_R); + + moveTopButton.addActionListener(e -> moveTop()); + moveTopButton.setMnemonic(KeyEvent.VK_PAGE_UP); + moveTopButton.setEnabled(false); + moveBottomButton.addActionListener(e -> moveBottom()); + moveBottomButton.setMnemonic(KeyEvent.VK_PAGE_DOWN); + moveBottomButton.setEnabled(false); + moveUpButton.addActionListener(e -> moveUp()); + moveUpButton.setMnemonic(KeyEvent.VK_UP); + moveUpButton.setEnabled(false); + moveDownButton.addActionListener(e -> moveDown()); + moveDownButton.setMnemonic(KeyEvent.VK_DOWN); + moveDownButton.setEnabled(false); + oneUnitPerSheetCheck.setAlignmentX(JComponent.CENTER_ALIGNMENT); oneUnitPerSheetCheck.setToolTipText("When unchecked, the record sheets for some unit types may be printed on the same page. " + "Note that the result may depend on whether reference tables are printed. This can be changed in the Settings."); queuedUnitList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - queuedUnitList.addListSelectionListener(e -> removeButton.setEnabled(!queuedUnitList.isSelectionEmpty())); + queuedUnitList.addListSelectionListener(new OnSelectionChanged()); queuedUnitList.setVisibleRowCount(15); JPanel buttonPanel = new FixedXYPanel(new GridLayout(4, 1)); @@ -90,6 +123,14 @@ protected Container createCenterPane() { buttonPanel.add(addPageBreakButton); buttonPanel.add(removeButton); buttonPanel.setAlignmentY(JComponent.TOP_ALIGNMENT); + + JPanel moveButtonPanel = new FixedXYPanel(new GridLayout(4, 1)); + moveButtonPanel.add(moveTopButton); + moveButtonPanel.add(moveUpButton); + moveButtonPanel.add(moveDownButton); + moveButtonPanel.add(moveBottomButton); + moveButtonPanel.setAlignmentY(JComponent.TOP_ALIGNMENT); + JScrollPane queuedUnitListScrollPane = new JScrollPane(queuedUnitList); queuedUnitListScrollPane.setAlignmentY(JComponent.TOP_ALIGNMENT); queuedUnitListScrollPane.setBorder(new TitledBorder("Selected Units:")); @@ -97,6 +138,7 @@ protected Container createCenterPane() { Box centerPanel = Box.createHorizontalBox(); centerPanel.add(buttonPanel); centerPanel.add(Box.createHorizontalStrut(30)); + centerPanel.add(moveButtonPanel); centerPanel.add(queuedUnitListScrollPane); centerPanel.setBorder(new EmptyBorder(20, 30, 20, 30)); @@ -215,6 +257,110 @@ private void removeSelectedUnits() { refresh(); } + private void moveTop() { + List newListTop = new ArrayList<>(); + List newListBottom = new ArrayList<>(); + boolean state = false; + for (int i = 0; i < units.size(); i++) { + if (i == topSelectedIndex()) { + state = true; + } else if (i > bottomSelectedIndex()) { + state = false; + } + (state ? newListTop : newListBottom).add(units.get(i)); + } + units.clear(); + units.addAll(newListTop); + units.addAll(newListBottom); + refresh(); + queuedUnitList.setSelectedIndices(IntStream.range(0, newListTop.size()).toArray()); + } + + private void moveBottom() { + List newListBottom = new ArrayList<>(); + List newListTop = new ArrayList<>(); + boolean state = false; + for (int i = 0; i < units.size(); i++) { + if (i == topSelectedIndex()) { + state = true; + } else if (i > bottomSelectedIndex()) { + state = false; + } + (state ? newListBottom : newListTop).add(units.get(i)); + } + units.clear(); + units.addAll(newListTop); + units.addAll(newListBottom); + refresh(); + queuedUnitList.setSelectedIndices(IntStream.range(newListTop.size(), newListTop.size() + newListBottom.size()).toArray()); + } + + private void moveUp() { + var unit = units.remove(topSelectedIndex() - 1); + units.add(bottomSelectedIndex(), unit); + var indices = queuedUnitList.getSelectedIndices(); + refresh(); + queuedUnitList.setSelectedIndices(Arrays.stream(indices).map(i -> i - 1).toArray()); + } + + private void moveDown() { + var unit = units.remove(bottomSelectedIndex() + 1); + units.add(topSelectedIndex(), unit); + var indices = queuedUnitList.getSelectedIndices(); + refresh(); + queuedUnitList.setSelectedIndices(Arrays.stream(indices).map(i -> i + 1).toArray()); + } + + private int topSelectedIndex() { + return queuedUnitList.getSelectedIndex(); + } + + private int bottomSelectedIndex() { + var indices = queuedUnitList.getSelectedIndices(); + return indices[indices.length - 1]; + } + + private class OnSelectionChanged implements ListSelectionListener { + @Override + public void valueChanged(ListSelectionEvent e) { + removeButton.setEnabled(!queuedUnitList.isSelectionEmpty()); + + if (!isSelectionContiguous()) { + moveTopButton.setEnabled(false); + moveUpButton.setEnabled(false); + moveDownButton.setEnabled(false); + moveBottomButton.setEnabled(false); + } else { + if (topSelectedIndex() == 0) { + moveTopButton.setEnabled(false); + moveUpButton.setEnabled(false); + } else { + moveTopButton.setEnabled(true); + moveUpButton.setEnabled(true); + } + if (bottomSelectedIndex() == units.size() - 1) { + moveBottomButton.setEnabled(false); + moveDownButton.setEnabled(false); + } else { + moveBottomButton.setEnabled(true); + moveDownButton.setEnabled(true); + } + } + } + + private boolean isSelectionContiguous() { + // getSelectedIndices is guaranteed to return the indices in ascending order + var indices = queuedUnitList.getSelectedIndices(); + if (indices.length == 0) { + return false; + } + + var start = indices[0]; + var end = indices[indices.length - 1]; + return end - start == indices.length - 1; + } + } + // TODO: Move to UIUtil public static class FixedXYPanel extends JPanel {