mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Add shift+click multi-select to custom quest format dialog
This commit is contained in:
@@ -17,136 +17,155 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DialogChooseSets {
|
public class DialogChooseSets {
|
||||||
private final List<String> selectedSets = new ArrayList<>();
|
private final List<String> selectedSets = new ArrayList<>();
|
||||||
private boolean wantReprints = true;
|
private boolean wantReprints = true;
|
||||||
private Runnable okCallback;
|
private Runnable okCallback;
|
||||||
|
|
||||||
private final List<FCheckBox> choices = new ArrayList<>();
|
private final List<FCheckBox> choices = new ArrayList<>();
|
||||||
private final FCheckBox cbWantReprints = new FCheckBox("Allow compatible reprints from other sets");
|
private final FCheckBox cbWantReprints = new FCheckBox("Allow compatible reprints from other sets");
|
||||||
|
|
||||||
// lists are of set codes (e.g. "2ED")
|
// lists are of set codes (e.g. "2ED")
|
||||||
public DialogChooseSets(
|
public DialogChooseSets(
|
||||||
Collection<String> preselectedSets, Collection<String> unselectableSets, boolean showWantReprintsCheckbox) {
|
Collection<String> preselectedSets, Collection<String> unselectableSets, boolean showWantReprintsCheckbox) {
|
||||||
|
|
||||||
// create a local copy of the editions list so we can sort it
|
// create a local copy of the editions list so we can sort it
|
||||||
List<CardEdition> editions = new ArrayList<>();
|
List<CardEdition> editions = new ArrayList<>();
|
||||||
for (CardEdition ce : FModel.getMagicDb().getEditions()) {
|
for (CardEdition ce : FModel.getMagicDb().getEditions()) {
|
||||||
editions.add(ce);
|
editions.add(ce);
|
||||||
}
|
}
|
||||||
Collections.sort(editions);
|
Collections.sort(editions);
|
||||||
Collections.reverse(editions);
|
Collections.reverse(editions);
|
||||||
|
|
||||||
List<FCheckBox> coreSets = new ArrayList<>();
|
List<FCheckBox> coreSets = new ArrayList<>();
|
||||||
List<FCheckBox> expansionSets = new ArrayList<>();
|
List<FCheckBox> expansionSets = new ArrayList<>();
|
||||||
List<FCheckBox> otherSets = new ArrayList<>();
|
List<FCheckBox> otherSets = new ArrayList<>();
|
||||||
|
|
||||||
for (CardEdition ce : editions) {
|
for (CardEdition ce : editions) {
|
||||||
String code = ce.getCode();
|
|
||||||
FCheckBox box = new FCheckBox(String.format("%s (%s)", ce.getName(), code));
|
|
||||||
box.setName(code);
|
|
||||||
box.setSelected(null != preselectedSets && preselectedSets.contains(code));
|
|
||||||
box.setEnabled(null == unselectableSets || !unselectableSets.contains(code));
|
|
||||||
switch (ce.getType()) {
|
|
||||||
case CORE: coreSets.add(box); break;
|
|
||||||
case EXPANSION: expansionSets.add(box); break;
|
|
||||||
default: otherSets.add(box); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FPanel p = new FPanel(new MigLayout("insets 0, gap 0, center, wrap 3"));
|
String code = ce.getCode();
|
||||||
p.setOpaque(false);
|
FCheckBox box = new FCheckBox(String.format("%s (%s)", ce.getName(), code));
|
||||||
p.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
|
||||||
|
|
||||||
p.add(new FLabel.Builder().text("Choose sets").fontSize(18).build(), "center, span, wrap, gaptop 10");
|
box.setName(code);
|
||||||
|
box.setSelected(null != preselectedSets && preselectedSets.contains(code));
|
||||||
|
box.setEnabled(null == unselectableSets || !unselectableSets.contains(code));
|
||||||
|
|
||||||
String constraints = "aligny top";
|
switch (ce.getType()) {
|
||||||
p.add(makeCheckBoxList(coreSets, "Core sets", true), constraints);
|
case CORE:
|
||||||
p.add(makeCheckBoxList(expansionSets, "Expansions", false), constraints);
|
coreSets.add(box);
|
||||||
p.add(makeCheckBoxList(otherSets, "Other sets", false), constraints);
|
break;
|
||||||
|
case EXPANSION:
|
||||||
|
expansionSets.add(box);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
otherSets.add(box);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
|
}
|
||||||
overlay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax center, ay center"));
|
|
||||||
|
|
||||||
final Runnable cleanup = new Runnable() {
|
FPanel panel = new FPanel(new MigLayout("insets 0, gap 0, center, wrap 3"));
|
||||||
@Override
|
panel.setOpaque(false);
|
||||||
public void run() {
|
panel.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
||||||
SOverlayUtils.hideOverlay();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FButton btnOk = new FButton("OK");
|
panel.add(new FLabel.Builder().text("Choose sets").fontSize(18).build(), "center, span, wrap, gaptop 10");
|
||||||
btnOk.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
|
||||||
cleanup.run();
|
|
||||||
handleOk();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
FButton btnCancel = new FButton("Cancel");
|
String constraints = "aligny top";
|
||||||
btnCancel.addActionListener(new ActionListener() {
|
panel.add(makeCheckBoxList(coreSets, "Core sets", true), constraints);
|
||||||
@Override
|
panel.add(makeCheckBoxList(expansionSets, "Expansions", false), constraints);
|
||||||
public void actionPerformed(ActionEvent e) {
|
panel.add(makeCheckBoxList(otherSets, "Other sets", false), constraints);
|
||||||
cleanup.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 20, ax center"));
|
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
|
||||||
southPanel.setOpaque(false);
|
overlay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax center, ay center"));
|
||||||
if (showWantReprintsCheckbox) {
|
|
||||||
southPanel.add(cbWantReprints, "center, span, wrap");
|
|
||||||
}
|
|
||||||
southPanel.add(btnOk, "center, w 40%, h 20!");
|
|
||||||
southPanel.add(btnCancel, "center, w 40%, h 20!");
|
|
||||||
|
|
||||||
p.add(southPanel, "dock south, gapBottom 10");
|
final Runnable cleanup = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SOverlayUtils.hideOverlay();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
overlay.add(p);
|
FButton btnOk = new FButton("OK");
|
||||||
p.getRootPane().setDefaultButton(btnOk);
|
btnOk.addActionListener(new ActionListener() {
|
||||||
SOverlayUtils.showOverlay();
|
@Override
|
||||||
}
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
cleanup.run();
|
||||||
|
handleOk();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
public void setOkCallback(Runnable onOk) {
|
FButton btnCancel = new FButton("Cancel");
|
||||||
okCallback = onOk;
|
btnCancel.addActionListener(new ActionListener() {
|
||||||
}
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
cleanup.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// result accessors
|
JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 20, ax center"));
|
||||||
public List<String> getSelectedSets() { return selectedSets; }
|
southPanel.setOpaque(false);
|
||||||
public boolean getWantReprints() { return wantReprints; }
|
if (showWantReprintsCheckbox) {
|
||||||
|
southPanel.add(cbWantReprints, "center, span, wrap");
|
||||||
|
}
|
||||||
|
southPanel.add(btnOk, "center, w 40%, h 20!");
|
||||||
|
southPanel.add(btnCancel, "center, w 40%, h 20!");
|
||||||
|
|
||||||
private JPanel makeCheckBoxList(List<FCheckBox> sets, String title, boolean focused) {
|
panel.add(southPanel, "dock south, gapBottom 10");
|
||||||
choices.addAll(sets);
|
|
||||||
final FCheckBoxList<FCheckBox> cbl = new FCheckBoxList<>(false);
|
|
||||||
cbl.setListData(sets.toArray(new FCheckBox[sets.size()]));
|
|
||||||
cbl.setVisibleRowCount(Math.min(20, sets.size()));
|
|
||||||
|
|
||||||
if (focused) {
|
overlay.add(panel);
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
panel.getRootPane().setDefaultButton(btnOk);
|
||||||
@Override
|
SOverlayUtils.showOverlay();
|
||||||
public void run() {
|
|
||||||
cbl.requestFocusInWindow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
JPanel pnl = new JPanel(new MigLayout("center, wrap"));
|
}
|
||||||
pnl.setOpaque(false);
|
|
||||||
pnl.add(new FLabel.Builder().text(title).build());
|
|
||||||
pnl.add(new FScrollPane(cbl, true));
|
|
||||||
return pnl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleOk() {
|
public void setOkCallback(Runnable onOk) {
|
||||||
for (FCheckBox box : choices) {
|
okCallback = onOk;
|
||||||
if (box.isSelected()) {
|
}
|
||||||
selectedSets.add(box.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
wantReprints = cbWantReprints.isSelected();
|
public List<String> getSelectedSets() {
|
||||||
}
|
return selectedSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getWantReprints() {
|
||||||
|
return wantReprints;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JPanel makeCheckBoxList(List<FCheckBox> sets, String title, boolean focused) {
|
||||||
|
|
||||||
|
choices.addAll(sets);
|
||||||
|
final FCheckBoxList<FCheckBox> cbl = new FCheckBoxList<>(false);
|
||||||
|
cbl.setListData(sets.toArray(new FCheckBox[sets.size()]));
|
||||||
|
cbl.setVisibleRowCount(Math.min(20, sets.size()));
|
||||||
|
|
||||||
|
if (focused) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
cbl.requestFocusInWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
JPanel pnl = new JPanel(new MigLayout("center, wrap"));
|
||||||
|
pnl.setOpaque(false);
|
||||||
|
pnl.add(new FLabel.Builder().text(title).build());
|
||||||
|
pnl.add(new FScrollPane(cbl, true));
|
||||||
|
return pnl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOk() {
|
||||||
|
|
||||||
|
for (FCheckBox box : choices) {
|
||||||
|
if (box.isSelected()) {
|
||||||
|
selectedSets.add(box.getName());
|
||||||
|
}
|
||||||
|
wantReprints = cbWantReprints.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != okCallback) {
|
||||||
|
okCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (null != okCallback) {
|
|
||||||
okCallback.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,153 @@
|
|||||||
package forge.toolbox;
|
package forge.toolbox;
|
||||||
|
|
||||||
import java.awt.Component;
|
import javax.swing.*;
|
||||||
import java.awt.event.FocusEvent;
|
|
||||||
import java.awt.event.FocusListener;
|
|
||||||
import java.awt.event.KeyAdapter;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.ListCellRenderer;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of FCheckBox items using Forge skin properties.
|
* A list of FCheckBox items using Forge skin properties.
|
||||||
* Call setListData() with an array of FCheckBox items to populate.
|
* Call setListData() with an array of FCheckBox items to populate.
|
||||||
*
|
* <p>
|
||||||
* based on code at http://www.devx.com/tips/Tip/5342
|
* based on code at http://www.devx.com/tips/Tip/5342
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class FCheckBoxList<E> extends JList<E> {
|
public class FCheckBoxList<E> extends JList<E> {
|
||||||
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
|
|
||||||
|
|
||||||
public FCheckBoxList(final boolean keepSelectionWhenFocusLost) {
|
private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
|
||||||
setCellRenderer(new CellRenderer<E>());
|
|
||||||
|
|
||||||
addMouseListener(new MouseAdapter() {
|
private int lastClickedIndex = 0;
|
||||||
@Override
|
private int currentShiftSelectionMinIndex = Integer.MAX_VALUE;
|
||||||
public void mousePressed(final MouseEvent e) {
|
private int currentShiftSelectionMaxIndex = -1;
|
||||||
final int index = locationToIndex(e.getPoint());
|
private int currentHighlightMinIndex = Integer.MAX_VALUE;
|
||||||
|
private int currentHighlightMaxIndex = -1;
|
||||||
|
private boolean shiftSelectShouldCheckBox = true;
|
||||||
|
|
||||||
if (index != -1) {
|
public FCheckBoxList(final boolean keepSelectionWhenFocusLost) {
|
||||||
final FCheckBox checkbox = (FCheckBox)getModel().getElementAt(index);
|
|
||||||
if (checkbox.isEnabled()) {
|
|
||||||
checkbox.setSelected(!checkbox.isSelected());
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addKeyListener(new KeyAdapter() {
|
setCellRenderer(new CellRenderer<E>());
|
||||||
@Override
|
|
||||||
public void keyPressed(final KeyEvent e) {
|
|
||||||
if (e.getKeyChar() == ' ') {
|
|
||||||
final FCheckBox item = (FCheckBox)getSelectedValue();
|
|
||||||
if (null == item || !item.isEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.setSelected(!item.isSelected());
|
addMouseListener(new MouseAdapter() {
|
||||||
repaint();
|
@Override
|
||||||
}
|
public void mousePressed(final MouseEvent e) {
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!keepSelectionWhenFocusLost) {
|
final int index = locationToIndex(e.getPoint());
|
||||||
addFocusListener(new FocusListener() {
|
|
||||||
int lastSelectedIdx;
|
|
||||||
|
|
||||||
@Override
|
if (index != -1) {
|
||||||
public void focusLost(final FocusEvent arg0) {
|
|
||||||
lastSelectedIdx = Math.max(0, getSelectedIndex());
|
|
||||||
clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (e.isShiftDown()) {
|
||||||
public void focusGained(final FocusEvent arg0) {
|
|
||||||
if (-1 == getSelectedIndex()) {
|
|
||||||
setSelectedIndex(lastSelectedIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
int min = Math.min(lastClickedIndex, index);
|
||||||
}
|
int max = Math.max(lastClickedIndex, index);
|
||||||
|
|
||||||
|
if (index == lastClickedIndex) {
|
||||||
|
currentHighlightMinIndex = lastClickedIndex;
|
||||||
|
currentHighlightMaxIndex = lastClickedIndex;
|
||||||
|
} else if (index > lastClickedIndex) {
|
||||||
|
currentHighlightMinIndex = lastClickedIndex;
|
||||||
|
currentHighlightMaxIndex = index;
|
||||||
|
} else if (index < lastClickedIndex) {
|
||||||
|
currentHighlightMinIndex = index;
|
||||||
|
currentHighlightMaxIndex = lastClickedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentShiftSelectionMinIndex = Math.min(min, currentShiftSelectionMinIndex);
|
||||||
|
currentShiftSelectionMaxIndex = Math.max(max, currentShiftSelectionMaxIndex);
|
||||||
|
|
||||||
|
for (int i = currentShiftSelectionMinIndex; i <= currentShiftSelectionMaxIndex; i++) {
|
||||||
|
final FCheckBox checkbox = (FCheckBox) getModel().getElementAt(i);
|
||||||
|
if (shiftSelectShouldCheckBox) {
|
||||||
|
checkbox.setSelected(!shiftSelectShouldCheckBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = min; i <= max; i++) {
|
||||||
|
final FCheckBox checkbox = (FCheckBox) getModel().getElementAt(i);
|
||||||
|
checkbox.setSelected(shiftSelectShouldCheckBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final FCheckBox checkbox = (FCheckBox) getModel().getElementAt(index);
|
||||||
|
|
||||||
|
if (checkbox.isEnabled()) {
|
||||||
|
checkbox.setSelected(!checkbox.isSelected());
|
||||||
|
shiftSelectShouldCheckBox = checkbox.isSelected();
|
||||||
|
lastClickedIndex = index;
|
||||||
|
currentShiftSelectionMinIndex = currentHighlightMinIndex = Integer.MAX_VALUE;
|
||||||
|
currentShiftSelectionMaxIndex = currentHighlightMaxIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyPressed(final KeyEvent e) {
|
||||||
|
if (e.getKeyChar() == ' ') {
|
||||||
|
final FCheckBox item = (FCheckBox) getSelectedValue();
|
||||||
|
if (null == item || !item.isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setSelected(!item.isSelected());
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!keepSelectionWhenFocusLost) {
|
||||||
|
addFocusListener(new FocusListener() {
|
||||||
|
int lastSelectedIdx;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void focusLost(final FocusEvent arg0) {
|
||||||
|
lastSelectedIdx = Math.max(0, getSelectedIndex());
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void focusGained(final FocusEvent arg0) {
|
||||||
|
if (getSelectedIndex() == -1) {
|
||||||
|
setSelectedIndex(lastSelectedIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class CellRenderer<E1> implements ListCellRenderer<E1> {
|
||||||
|
@Override
|
||||||
|
public Component getListCellRendererComponent(final JList<? extends E1> list, final E1 value, final int index, final boolean isSelected, final boolean cellHasFocus) {
|
||||||
|
|
||||||
|
final FCheckBox checkbox = (FCheckBox) value;
|
||||||
|
|
||||||
|
if (index >= currentHighlightMinIndex && index <= currentHighlightMaxIndex) {
|
||||||
|
checkbox.setOpaque(true);
|
||||||
|
} else {
|
||||||
|
checkbox.setOpaque(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox.setForeground(isSelected ? getSelectionForeground() : getForeground());
|
||||||
|
checkbox.setBackground(getSelectionBackground());
|
||||||
|
checkbox.setFont(getFont());
|
||||||
|
checkbox.setFocusPainted(false);
|
||||||
|
checkbox.setBorderPainted(true);
|
||||||
|
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : NO_FOCUS_BORDER);
|
||||||
|
|
||||||
|
return checkbox;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class CellRenderer<E1> implements ListCellRenderer<E1> {
|
|
||||||
@Override
|
|
||||||
public Component getListCellRendererComponent(final JList<? extends E1> list, final E1 value, final int index, final boolean isSelected, final boolean cellHasFocus) {
|
|
||||||
final FCheckBox checkbox = (FCheckBox)value;
|
|
||||||
checkbox.setBackground(isSelected ? getSelectionBackground() : getBackground());
|
|
||||||
checkbox.setForeground(isSelected ? getSelectionForeground() : getForeground());
|
|
||||||
checkbox.setFont(getFont());
|
|
||||||
checkbox.setFocusPainted(false);
|
|
||||||
checkbox.setBorderPainted(true);
|
|
||||||
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
|
|
||||||
return checkbox;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user