mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Skin ListChooser
This commit is contained in:
@@ -14,6 +14,10 @@ Support resetting and hiding filters
|
||||
Full catalog now available for sideboarding in Deck Editor
|
||||
Title field and buttons now available on Current Deck pane when on other sections, with the current section name displaying above the table
|
||||
|
||||
- More skinned dialogs -
|
||||
Most remaining dialogs are now skinned, including all message, confirmation, input, and list choice dialogs
|
||||
|
||||
|
||||
- Constructed mode -
|
||||
Recently a change was made to the constructed mode and this change now allows you to have up to 8 players rather than just two. The game formats that are located in the variants mode also allow up to eight players. The current user interface for this feature is fairly basic and is not very attractive. The settings tab allows you to set the number of opponents. The player tabs includes the same options that you used to see in the constructed mode.
|
||||
|
||||
|
||||
@@ -101,19 +101,18 @@ public class GuiChoose {
|
||||
}
|
||||
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
if (null == choices || choices.isEmpty()) {
|
||||
if (0 == min) {
|
||||
if (choices == null || choices.isEmpty()) {
|
||||
if (min == 0) {
|
||||
return new ArrayList<T>();
|
||||
} else {
|
||||
throw new RuntimeException("choice required from empty list");
|
||||
}
|
||||
throw new RuntimeException("choice required from empty list");
|
||||
}
|
||||
|
||||
Callable<List<T>> showChoice = new Callable<List<T>>() {
|
||||
@Override
|
||||
public List<T> call() {
|
||||
ListChooser<T> c = new ListChooser<T>(message, min, max, choices, display);
|
||||
final JList<T> list = c.getJList();
|
||||
final JList<T> list = c.getLstChoices();
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(final ListSelectionEvent ev) {
|
||||
@@ -121,7 +120,8 @@ public class GuiChoose {
|
||||
Card card = (Card) list.getSelectedValue();
|
||||
if (card.isFaceDown() && Singletons.getControl().mayShowCard(card)) {
|
||||
CMatchUI.SINGLETON_INSTANCE.setCard(card, true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
CMatchUI.SINGLETON_INSTANCE.setCard(card);
|
||||
}
|
||||
|
||||
@@ -134,10 +134,12 @@ public class GuiChoose {
|
||||
}
|
||||
});
|
||||
|
||||
if(selected != null)
|
||||
if (selected != null) {
|
||||
c.show(selected);
|
||||
else
|
||||
}
|
||||
else {
|
||||
c.show();
|
||||
}
|
||||
|
||||
GuiUtils.clearPanelSelections();
|
||||
return c.getSelectedValues();
|
||||
|
||||
@@ -19,22 +19,17 @@
|
||||
package forge.gui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.ListSelectionModel;
|
||||
@@ -46,6 +41,9 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.gui.toolbox.FList;
|
||||
import forge.gui.toolbox.FMouseAdapter;
|
||||
import forge.gui.toolbox.FOptionPane;
|
||||
|
||||
/**
|
||||
* A simple class that shows a list of choices in a dialog. Two properties
|
||||
@@ -71,61 +69,70 @@ import forge.FThreads;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ListChooser<T> {
|
||||
|
||||
// Data and number of choices for the list
|
||||
private List<T> list;
|
||||
private int minChoices, maxChoices;
|
||||
|
||||
// Decoration
|
||||
private String title;
|
||||
|
||||
// Flag: was the dialog already shown?
|
||||
private boolean called;
|
||||
|
||||
// initialized before; listeners may be added to it
|
||||
private JList<T> jList;
|
||||
// Temporarily stored for event handlers during show
|
||||
private JDialog dialog;
|
||||
private JOptionPane optionPane;
|
||||
private Action ok, cancel;
|
||||
private FList<T> lstChoices;
|
||||
private FOptionPane optionPane;
|
||||
|
||||
public ListChooser(final String title, final int minChoices, final int maxChoices, final Collection<T> list, final Function<T, String> display) {
|
||||
FThreads.assertExecutedByEdt(true);
|
||||
this.title = title;
|
||||
this.minChoices = minChoices;
|
||||
this.maxChoices = maxChoices;
|
||||
this.list = list.getClass().isInstance(List.class) ? (List<T>)list : Lists.newArrayList(list);
|
||||
this.jList = new JList<T>(new ChooserListModel());
|
||||
this.ok = new CloseAction(JOptionPane.OK_OPTION, "OK");
|
||||
this.ok.setEnabled(minChoices == 0);
|
||||
this.cancel = new CloseAction(JOptionPane.CANCEL_OPTION, "Cancel");
|
||||
this.lstChoices = new FList<T>(new ChooserListModel());
|
||||
|
||||
Object[] options;
|
||||
String[] options;
|
||||
if (minChoices == 0) {
|
||||
options = new Object[] { new JButton(this.ok), new JButton(this.cancel) };
|
||||
} else {
|
||||
options = new Object[] { new JButton(this.ok) };
|
||||
options = new String[] {"OK","Cancel"};
|
||||
}
|
||||
else {
|
||||
options = new String[] {"OK"};
|
||||
}
|
||||
|
||||
if (maxChoices == 1) {
|
||||
this.jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
this.lstChoices.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
}
|
||||
|
||||
if( null != display )
|
||||
this.jList.setCellRenderer(new TransformedCellRenderer(display));
|
||||
if (display != null) {
|
||||
this.lstChoices.setCellRenderer(new TransformedCellRenderer(display));
|
||||
}
|
||||
|
||||
this.optionPane = new JOptionPane(new JScrollPane(this.jList), JOptionPane.QUESTION_MESSAGE,
|
||||
JOptionPane.DEFAULT_OPTION, null, options, options[0]);
|
||||
this.jList.getSelectionModel().addListSelectionListener(new SelListener());
|
||||
this.jList.addMouseListener(new DblListener());
|
||||
this.optionPane = new FOptionPane(null, title, null, new JScrollPane(this.lstChoices), options, 0);
|
||||
this.optionPane.setButtonEnabled(0, minChoices == 0);
|
||||
|
||||
this.lstChoices.getSelectionModel().addListSelectionListener(new SelListener());
|
||||
this.lstChoices.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
ListChooser.this.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.lstChoices.addMouseListener(new FMouseAdapter() {
|
||||
@Override
|
||||
public void onLeftClick(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
ListChooser.this.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JList used in the list chooser. this is useful for
|
||||
* Returns the FList used in the list chooser. this is useful for
|
||||
* registering listeners before showing the dialog.
|
||||
*
|
||||
* @return a {@link javax.swing.JList} object.
|
||||
*/
|
||||
public JList<T> getJList() {
|
||||
return this.jList;
|
||||
public FList<T> getLstChoices() {
|
||||
return this.lstChoices;
|
||||
}
|
||||
|
||||
/** @return boolean */
|
||||
@@ -143,42 +150,45 @@ public class ListChooser<T> {
|
||||
if (this.called) {
|
||||
throw new IllegalStateException("Already shown");
|
||||
}
|
||||
Integer value;
|
||||
int result;
|
||||
do {
|
||||
this.dialog = this.optionPane.createDialog(JOptionPane.getRootFrame(), this.title);
|
||||
if (this.minChoices != 0) {
|
||||
this.dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
this.optionPane.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
}
|
||||
|
||||
if (list.contains(item)) {
|
||||
jList.setSelectedValue(item, true);
|
||||
} else {
|
||||
jList.setSelectedIndex(0);
|
||||
lstChoices.setSelectedValue(item, true);
|
||||
}
|
||||
else {
|
||||
lstChoices.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
this.dialog.addWindowFocusListener(new WindowFocusListener() {
|
||||
this.optionPane.addWindowFocusListener(new WindowFocusListener() {
|
||||
@Override
|
||||
public void windowGainedFocus(final WindowEvent e) {
|
||||
ListChooser.this.jList.grabFocus();
|
||||
ListChooser.this.lstChoices.grabFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowLostFocus(final WindowEvent e) {
|
||||
}
|
||||
});
|
||||
this.dialog.setVisible(true);
|
||||
this.dialog.dispose();
|
||||
value = (Integer) this.optionPane.getValue();
|
||||
if ((value == null) || (value != JOptionPane.OK_OPTION)) {
|
||||
this.jList.clearSelection();
|
||||
// can't stop closing by ESC, so repeat if cancelled
|
||||
this.optionPane.setVisible(true);
|
||||
result = this.optionPane.getResult();
|
||||
if (result != 0) {
|
||||
this.lstChoices.clearSelection();
|
||||
break;
|
||||
}
|
||||
} while ((this.minChoices != 0) && (value != JOptionPane.OK_OPTION));
|
||||
// can't stop closing by ESC, so repeat if cancelled
|
||||
} while (this.minChoices != 0);
|
||||
|
||||
this.optionPane.dispose();
|
||||
|
||||
// this assert checks if we really don't return on a cancel if input is
|
||||
// mandatory
|
||||
assert (this.minChoices == 0) || (value == JOptionPane.OK_OPTION);
|
||||
assert (this.minChoices == 0) || (result == 0);
|
||||
this.called = true;
|
||||
return (value != null) && (value == JOptionPane.OK_OPTION);
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +201,7 @@ public class ListChooser<T> {
|
||||
if (!this.called) {
|
||||
throw new IllegalStateException("not yet shown");
|
||||
}
|
||||
return (Integer) this.optionPane.getValue() == JOptionPane.OK_OPTION;
|
||||
return (this.optionPane.getResult() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +213,7 @@ public class ListChooser<T> {
|
||||
if (!this.called) {
|
||||
throw new IllegalStateException("not yet shown");
|
||||
}
|
||||
return this.jList.getSelectedIndices();
|
||||
return this.lstChoices.getSelectedIndices();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +226,7 @@ public class ListChooser<T> {
|
||||
if (!this.called) {
|
||||
throw new IllegalStateException("not yet shown");
|
||||
}
|
||||
return this.jList.getSelectedValuesList();
|
||||
return this.lstChoices.getSelectedValuesList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +238,7 @@ public class ListChooser<T> {
|
||||
if (!this.called) {
|
||||
throw new IllegalStateException("not yet shown");
|
||||
}
|
||||
return this.jList.getSelectedIndex();
|
||||
return this.lstChoices.getSelectedIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +250,7 @@ public class ListChooser<T> {
|
||||
if (!this.called) {
|
||||
throw new IllegalStateException("not yet shown");
|
||||
}
|
||||
return (T) this.jList.getSelectedValue();
|
||||
return (T) this.lstChoices.getSelectedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,13 +259,12 @@ public class ListChooser<T> {
|
||||
* </p>
|
||||
*/
|
||||
private void commit() {
|
||||
if (this.ok.isEnabled()) {
|
||||
this.optionPane.setValue(JOptionPane.OK_OPTION);
|
||||
if (this.optionPane.isButtonEnabled(0)) {
|
||||
optionPane.setResult(0);
|
||||
}
|
||||
}
|
||||
|
||||
private class ChooserListModel extends AbstractListModel<T> {
|
||||
|
||||
private static final long serialVersionUID = 3871965346333840556L;
|
||||
|
||||
@Override
|
||||
@@ -269,38 +278,11 @@ public class ListChooser<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = -8426767786083886936L;
|
||||
private final int value;
|
||||
|
||||
public CloseAction(final int value, final String label) {
|
||||
super(label);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
ListChooser.this.optionPane.setValue(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
private class SelListener implements ListSelectionListener {
|
||||
|
||||
@Override
|
||||
public void valueChanged(final ListSelectionEvent e) {
|
||||
final int num = ListChooser.this.jList.getSelectedIndices().length;
|
||||
ListChooser.this.ok
|
||||
.setEnabled((num >= ListChooser.this.minChoices) && (num <= ListChooser.this.maxChoices));
|
||||
}
|
||||
}
|
||||
|
||||
private class DblListener extends MouseAdapter {
|
||||
@Override
|
||||
public void mouseClicked(final MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
ListChooser.this.commit();
|
||||
}
|
||||
final int num = ListChooser.this.lstChoices.getSelectedIndices().length;
|
||||
ListChooser.this.optionPane.setButtonEnabled(0, (num >= ListChooser.this.minChoices) && (num <= ListChooser.this.maxChoices));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,13 +302,9 @@ public class ListChooser<T> {
|
||||
* @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
|
||||
*/
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends T> list, T value, int index, boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(JList<? extends T> list, T value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
// TODO Auto-generated method stub
|
||||
return defRenderer.getListCellRendererComponent(list, transformer.apply(value), index, isSelected, cellHasFocus);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.event.MouseEvent;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
@@ -431,9 +432,16 @@ public class FLabel extends JLabel implements ILocalRepaint {
|
||||
public int getAutoSizeWidth() {
|
||||
int width = 0;
|
||||
if (this.getText() != null && !this.getText().isEmpty()) {
|
||||
FontMetrics metrics = this.getGraphics().getFontMetrics(this.getFont());
|
||||
Graphics g = this.getGraphics();
|
||||
if (g == null) {
|
||||
g = JOptionPane.getRootFrame().getGraphics(); //fallback to root frame's graphics if needed
|
||||
}
|
||||
FontMetrics metrics = g.getFontMetrics(this.getFont());
|
||||
width = metrics.stringWidth(this.getText());
|
||||
}
|
||||
if (this.getIcon() != null) {
|
||||
width += this.getIcon().getIconWidth() + this.getIconTextGap();
|
||||
}
|
||||
if (opaque) {
|
||||
width += 6; //account for border/padding if opaque
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class FList<E> extends JList<E> {
|
||||
lblItem.setBorder(new EmptyBorder(4, 3, 4, 3));
|
||||
lblItemSkin.setBackground(FSkin.getColor(hasFocus() ? FSkin.Colors.CLR_ACTIVE : FSkin.Colors.CLR_INACTIVE));
|
||||
lblItemSkin.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
|
||||
lblItemSkin.setFont(FSkin.getFont(13));
|
||||
lblItemSkin.setFont(FSkin.getFont(12));
|
||||
lblItem.setOpaque(isSelected);
|
||||
return lblItem;
|
||||
}
|
||||
|
||||
@@ -117,13 +117,7 @@ public class FOptionPane extends FDialog {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
SwingUtilities.invokeLater(new Runnable() { //delay so enter can confirm input choice first
|
||||
@Override
|
||||
public void run() {
|
||||
optionPane.result = 0;
|
||||
optionPane.setVisible(false);
|
||||
}
|
||||
});
|
||||
optionPane.setResult(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -142,8 +136,9 @@ public class FOptionPane extends FDialog {
|
||||
}
|
||||
|
||||
private int result = -1; //default result to -1, indicating dialog closed without choosing option
|
||||
private final FButton[] buttons;
|
||||
|
||||
private FOptionPane(String message, String title, SkinImage icon, Component comp, String[] options, int defaultOption) {
|
||||
public FOptionPane(String message, String title, SkinImage icon, Component comp, String[] options, int defaultOption) {
|
||||
this.setTitle(title);
|
||||
|
||||
int padding = 10;
|
||||
@@ -176,7 +171,7 @@ public class FOptionPane extends FDialog {
|
||||
FontMetrics metrics = JOptionPane.getRootFrame().getGraphics().getFontMetrics(btnMeasure.getFont());
|
||||
|
||||
int maxTextWidth = 0;
|
||||
final FButton[] buttons = new FButton[optionCount];
|
||||
buttons = new FButton[optionCount];
|
||||
for (int i = 0; i < optionCount; i++) {
|
||||
int textWidth = metrics.stringWidth(options[i]);
|
||||
if (textWidth > maxTextWidth) {
|
||||
@@ -252,4 +247,36 @@ public class FOptionPane extends FDialog {
|
||||
|
||||
this.setSize(width, this.getHeight() + buttonHeight); //resize dialog again to account for buttons
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (this.isVisible() == visible) { return; }
|
||||
|
||||
if (visible) {
|
||||
result = -1; //default result to -1 when shown, indicating dialog closed without choosing option
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
public int getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(int result0) {
|
||||
this.result = result0;
|
||||
SwingUtilities.invokeLater(new Runnable() { //delay hiding so action can finish first
|
||||
@Override
|
||||
public void run() {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isButtonEnabled(int index) {
|
||||
return buttons[index].isEnabled();
|
||||
}
|
||||
|
||||
public void setButtonEnabled(int index, boolean enabled) {
|
||||
buttons[index].setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package forge.view;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SpringLayout;
|
||||
|
||||
import forge.gui.toolbox.FSkin;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class FTitleBar extends FTitleBarBase {
|
||||
private static final FSkin.SkinFont skinFont = FSkin.getFont(12);
|
||||
|
||||
private final JLabel lblTitle = new JLabel();
|
||||
|
||||
|
||||
public FTitleBar(ITitleBarOwner owner0) {
|
||||
super(owner0);
|
||||
skin.setMatteBorder(0, 0, 1, 0, bottomEdgeColor);
|
||||
@@ -17,10 +23,10 @@ public class FTitleBar extends FTitleBarBase {
|
||||
setTitle(owner0.getTitle()); //set default title based on frame title
|
||||
setIconImage(owner0.getIconImage()); //set default icon image based on frame icon image
|
||||
FSkin.get(lblTitle).setForeground(foreColor);
|
||||
FSkin.get(lblTitle).setFont(FSkin.getFont(12));
|
||||
FSkin.get(lblTitle).setFont(skinFont);
|
||||
addControls();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void addControls() {
|
||||
add(lblTitle);
|
||||
@@ -32,8 +38,9 @@ public class FTitleBar extends FTitleBarBase {
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
this.lblTitle.setText(title);
|
||||
updatePreferredSize();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setIconImage(Image image) {
|
||||
if (image != null) {
|
||||
@@ -42,5 +49,15 @@ public class FTitleBar extends FTitleBarBase {
|
||||
else {
|
||||
this.lblTitle.setIcon(null);
|
||||
}
|
||||
updatePreferredSize();
|
||||
}
|
||||
|
||||
private void updatePreferredSize() {
|
||||
int width = skinFont.measureTextWidth(JOptionPane.getRootFrame().getGraphics(), this.lblTitle.getText());
|
||||
if (this.lblTitle.getIcon() != null) {
|
||||
width += this.lblTitle.getIcon().getIconWidth() + this.lblTitle.getIconTextGap();
|
||||
}
|
||||
width += btnClose.getPreferredSize().width;
|
||||
this.setPreferredSize(new Dimension(width + 10, visibleHeight));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user