mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +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;
|
||||
|
||||
public class DialogChooseSets {
|
||||
private final List<String> selectedSets = new ArrayList<>();
|
||||
private boolean wantReprints = true;
|
||||
private Runnable okCallback;
|
||||
private final List<String> selectedSets = new ArrayList<>();
|
||||
private boolean wantReprints = true;
|
||||
private Runnable okCallback;
|
||||
|
||||
private final List<FCheckBox> choices = new ArrayList<>();
|
||||
private final FCheckBox cbWantReprints = new FCheckBox("Allow compatible reprints from other sets");
|
||||
private final List<FCheckBox> choices = new ArrayList<>();
|
||||
private final FCheckBox cbWantReprints = new FCheckBox("Allow compatible reprints from other sets");
|
||||
|
||||
// lists are of set codes (e.g. "2ED")
|
||||
public DialogChooseSets(
|
||||
Collection<String> preselectedSets, Collection<String> unselectableSets, boolean showWantReprintsCheckbox) {
|
||||
// lists are of set codes (e.g. "2ED")
|
||||
public DialogChooseSets(
|
||||
Collection<String> preselectedSets, Collection<String> unselectableSets, boolean showWantReprintsCheckbox) {
|
||||
|
||||
// create a local copy of the editions list so we can sort it
|
||||
List<CardEdition> editions = new ArrayList<>();
|
||||
for (CardEdition ce : FModel.getMagicDb().getEditions()) {
|
||||
editions.add(ce);
|
||||
}
|
||||
Collections.sort(editions);
|
||||
Collections.reverse(editions);
|
||||
// create a local copy of the editions list so we can sort it
|
||||
List<CardEdition> editions = new ArrayList<>();
|
||||
for (CardEdition ce : FModel.getMagicDb().getEditions()) {
|
||||
editions.add(ce);
|
||||
}
|
||||
Collections.sort(editions);
|
||||
Collections.reverse(editions);
|
||||
|
||||
List<FCheckBox> coreSets = new ArrayList<>();
|
||||
List<FCheckBox> expansionSets = new ArrayList<>();
|
||||
List<FCheckBox> otherSets = new ArrayList<>();
|
||||
List<FCheckBox> coreSets = new ArrayList<>();
|
||||
List<FCheckBox> expansionSets = new ArrayList<>();
|
||||
List<FCheckBox> otherSets = new ArrayList<>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
for (CardEdition ce : editions) {
|
||||
|
||||
FPanel p = new FPanel(new MigLayout("insets 0, gap 0, center, wrap 3"));
|
||||
p.setOpaque(false);
|
||||
p.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
||||
String code = ce.getCode();
|
||||
FCheckBox box = new FCheckBox(String.format("%s (%s)", ce.getName(), code));
|
||||
|
||||
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";
|
||||
p.add(makeCheckBoxList(coreSets, "Core sets", true), constraints);
|
||||
p.add(makeCheckBoxList(expansionSets, "Expansions", false), constraints);
|
||||
p.add(makeCheckBoxList(otherSets, "Other sets", false), constraints);
|
||||
switch (ce.getType()) {
|
||||
case CORE:
|
||||
coreSets.add(box);
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
SOverlayUtils.hideOverlay();
|
||||
}
|
||||
};
|
||||
FPanel panel = new FPanel(new MigLayout("insets 0, gap 0, center, wrap 3"));
|
||||
panel.setOpaque(false);
|
||||
panel.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
||||
|
||||
FButton btnOk = new FButton("OK");
|
||||
btnOk.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
cleanup.run();
|
||||
handleOk();
|
||||
}
|
||||
});
|
||||
panel.add(new FLabel.Builder().text("Choose sets").fontSize(18).build(), "center, span, wrap, gaptop 10");
|
||||
|
||||
FButton btnCancel = new FButton("Cancel");
|
||||
btnCancel.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
cleanup.run();
|
||||
}
|
||||
});
|
||||
String constraints = "aligny top";
|
||||
panel.add(makeCheckBoxList(coreSets, "Core sets", true), constraints);
|
||||
panel.add(makeCheckBoxList(expansionSets, "Expansions", false), constraints);
|
||||
panel.add(makeCheckBoxList(otherSets, "Other sets", false), constraints);
|
||||
|
||||
JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 20, ax center"));
|
||||
southPanel.setOpaque(false);
|
||||
if (showWantReprintsCheckbox) {
|
||||
southPanel.add(cbWantReprints, "center, span, wrap");
|
||||
}
|
||||
southPanel.add(btnOk, "center, w 40%, h 20!");
|
||||
southPanel.add(btnCancel, "center, w 40%, h 20!");
|
||||
final JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
|
||||
overlay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax center, ay center"));
|
||||
|
||||
p.add(southPanel, "dock south, gapBottom 10");
|
||||
final Runnable cleanup = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SOverlayUtils.hideOverlay();
|
||||
}
|
||||
};
|
||||
|
||||
overlay.add(p);
|
||||
p.getRootPane().setDefaultButton(btnOk);
|
||||
SOverlayUtils.showOverlay();
|
||||
}
|
||||
FButton btnOk = new FButton("OK");
|
||||
btnOk.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
cleanup.run();
|
||||
handleOk();
|
||||
}
|
||||
});
|
||||
|
||||
public void setOkCallback(Runnable onOk) {
|
||||
okCallback = onOk;
|
||||
}
|
||||
FButton btnCancel = new FButton("Cancel");
|
||||
btnCancel.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
cleanup.run();
|
||||
}
|
||||
});
|
||||
|
||||
// result accessors
|
||||
public List<String> getSelectedSets() { return selectedSets; }
|
||||
public boolean getWantReprints() { return wantReprints; }
|
||||
JPanel southPanel = new JPanel(new MigLayout("insets 10, gap 20, ax center"));
|
||||
southPanel.setOpaque(false);
|
||||
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) {
|
||||
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()));
|
||||
panel.add(southPanel, "dock south, gapBottom 10");
|
||||
|
||||
if (focused) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cbl.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
overlay.add(panel);
|
||||
panel.getRootPane().setDefaultButton(btnOk);
|
||||
SOverlayUtils.showOverlay();
|
||||
|
||||
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());
|
||||
}
|
||||
public void setOkCallback(Runnable onOk) {
|
||||
okCallback = onOk;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import java.awt.Component;
|
||||
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.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
/**
|
||||
* A list of FCheckBox items using Forge skin properties.
|
||||
* Call setListData() with an array of FCheckBox items to populate.
|
||||
*
|
||||
* <p>
|
||||
* based on code at http://www.devx.com/tips/Tip/5342
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FCheckBoxList<E> extends JList<E> {
|
||||
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
|
||||
|
||||
public FCheckBoxList(final boolean keepSelectionWhenFocusLost) {
|
||||
setCellRenderer(new CellRenderer<E>());
|
||||
private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
final int index = locationToIndex(e.getPoint());
|
||||
private int lastClickedIndex = 0;
|
||||
private int currentShiftSelectionMinIndex = Integer.MAX_VALUE;
|
||||
private int currentShiftSelectionMaxIndex = -1;
|
||||
private int currentHighlightMinIndex = Integer.MAX_VALUE;
|
||||
private int currentHighlightMaxIndex = -1;
|
||||
private boolean shiftSelectShouldCheckBox = true;
|
||||
|
||||
if (index != -1) {
|
||||
final FCheckBox checkbox = (FCheckBox)getModel().getElementAt(index);
|
||||
if (checkbox.isEnabled()) {
|
||||
checkbox.setSelected(!checkbox.isSelected());
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
public FCheckBoxList(final boolean keepSelectionWhenFocusLost) {
|
||||
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(final KeyEvent e) {
|
||||
if (e.getKeyChar() == ' ') {
|
||||
final FCheckBox item = (FCheckBox)getSelectedValue();
|
||||
if (null == item || !item.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCellRenderer(new CellRenderer<E>());
|
||||
|
||||
item.setSelected(!item.isSelected());
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
|
||||
if (!keepSelectionWhenFocusLost) {
|
||||
addFocusListener(new FocusListener() {
|
||||
int lastSelectedIdx;
|
||||
final int index = locationToIndex(e.getPoint());
|
||||
|
||||
@Override
|
||||
public void focusLost(final FocusEvent arg0) {
|
||||
lastSelectedIdx = Math.max(0, getSelectedIndex());
|
||||
clearSelection();
|
||||
}
|
||||
if (index != -1) {
|
||||
|
||||
@Override
|
||||
public void focusGained(final FocusEvent arg0) {
|
||||
if (-1 == getSelectedIndex()) {
|
||||
setSelectedIndex(lastSelectedIdx);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (e.isShiftDown()) {
|
||||
|
||||
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