diff --git a/.gitattributes b/.gitattributes index 10c96d87d20..c087657278b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1182,6 +1182,7 @@ forge-gui-mobile/src/forge/toolbox/FTextField.java -text forge-gui-mobile/src/forge/toolbox/FToggleSwitch.java -text forge-gui-mobile/src/forge/toolbox/GuiChoose.java -text forge-gui-mobile/src/forge/toolbox/GuiDialog.java -text +forge-gui-mobile/src/forge/toolbox/ListChooser.java -text forge-gui-mobile/src/forge/util/LayoutHelper.java -text forge-gui-mobile/src/forge/util/PhysicsObject.java -text forge-gui-mobile/src/forge/util/Utils.java -text diff --git a/forge-gui-mobile/src/forge/error/BugReportDialog.java b/forge-gui-mobile/src/forge/error/BugReportDialog.java index 29c6473114b..0b17e29e476 100644 --- a/forge-gui-mobile/src/forge/error/BugReportDialog.java +++ b/forge-gui-mobile/src/forge/error/BugReportDialog.java @@ -11,7 +11,6 @@ import forge.assets.FSkinFont; import forge.assets.FSkinColor.Colors; import forge.toolbox.FOptionPane; import forge.toolbox.FScrollPane; -import forge.util.Callback; public class BugReportDialog extends FOptionPane { private static boolean dialogShown; @@ -34,7 +33,7 @@ public class BugReportDialog extends FOptionPane { } @Override - protected void onButtonClick(final int option, final Callback callback) { + public void setResult(final int option) { switch (option) { case 0: BugReporter.copyAndGoToForums(text); diff --git a/forge-gui-mobile/src/forge/toolbox/FOptionPane.java b/forge-gui-mobile/src/forge/toolbox/FOptionPane.java index 5956721b804..1a679d6968f 100644 --- a/forge-gui-mobile/src/forge/toolbox/FOptionPane.java +++ b/forge-gui-mobile/src/forge/toolbox/FOptionPane.java @@ -120,8 +120,9 @@ public class FOptionPane extends FDialog { private final FTextArea prompt; private final FDisplayObject displayObj; private final FButton[] buttons; + private final Callback callback; - public FOptionPane(String message, String title, FSkinImage icon, FDisplayObject displayObj0, String[] options, int defaultOption, final Callback callback) { + public FOptionPane(String message, String title, FSkinImage icon, FDisplayObject displayObj0, String[] options, int defaultOption, final Callback callback0) { super(title); if (icon != null) { @@ -144,6 +145,8 @@ public class FOptionPane extends FDialog { add(displayObj); } + callback = callback0; + int optionCount = options.length; buttons = new FButton[optionCount]; for (int i = 0; i < optionCount; i++) { @@ -151,13 +154,13 @@ public class FOptionPane extends FDialog { buttons[i] = add(new FButton(options[i], new FEventHandler() { @Override public void handleEvent(FEvent e) { - onButtonClick(option, callback); + setResult(option); } })); } } - protected void onButtonClick(final int option, final Callback callback) { + public void setResult(final int option) { hide(); if (callback != null) { callback.run(option); @@ -205,8 +208,12 @@ public class FOptionPane extends FDialog { promptHeight = prompt.getHeight(); } } + x = PADDING; - y += promptHeight + gapBottom; + if (promptHeight > 0) { + y += promptHeight + gapBottom; + } + if (displayObj != null) { displayObj.setBounds(x, y, width - 2 * x, displayObj.getHeight()); y += displayObj.getHeight() + gapBottom; diff --git a/forge-gui-mobile/src/forge/toolbox/GuiChoose.java b/forge-gui-mobile/src/forge/toolbox/GuiChoose.java index 1efd396f211..b39886c0c89 100644 --- a/forge-gui-mobile/src/forge/toolbox/GuiChoose.java +++ b/forge-gui-mobile/src/forge/toolbox/GuiChoose.java @@ -10,10 +10,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.*; -/** - * TODO: Write javadoc for this type. - * - */ + public class GuiChoose { /** @@ -239,65 +236,8 @@ public class GuiChoose { throw new RuntimeException("choice required from empty list"); } - //TODO: Remove this temporary code and uncomment below - int resultCount = min; - if (resultCount == 0 && max > 0) { - resultCount = 1; - } - List result = new ArrayList(); - for (T choice : choices) { - result.add(choice); - if (result.size() == resultCount) { - break; - } - } - callback.run(result); - - /*Callable> showChoice = new Callable>() { - @Override - public List call() { - ListChooser c = new ListChooser(message, min, max, choices, display); - final JList list = c.getLstChoices(); - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(final ListSelectionEvent ev) { - if (list.getSelectedValue() instanceof Card) { - Card card = (Card) list.getSelectedValue(); - if (card.isFaceDown() && FControl.mayShowCard(card)) { - CMatchUI.SINGLETON_INSTANCE.setCard(card, true); - } - else { - CMatchUI.SINGLETON_INSTANCE.setCard(card); - } - - GuiUtils.clearPanelSelections(); - GuiUtils.setPanelSelection(card); - } - if (list.getSelectedValue() instanceof InventoryItem) { - CMatchUI.SINGLETON_INSTANCE.setCard((InventoryItem) list.getSelectedValue()); - } - } - }); - - if (selected != null) { - c.show(selected); - } - else { - c.show(); - } - - GuiUtils.clearPanelSelections(); - return c.getSelectedValues(); - } - }; - - FutureTask> future = new FutureTask>(showChoice); - FThreads.invokeInEdtAndWait(future); - try { - return future.get(); - } catch (Exception e) { // should be no exception here - e.printStackTrace(); - }*/ + ListChooser c = new ListChooser(message, min, max, choices, display, callback); + c.show(selected); } public static void many(final String title, final String topCaption, int cnt, final List sourceChoices, Card referenceCard, final Callback> callback) { diff --git a/forge-gui-mobile/src/forge/toolbox/GuiDialog.java b/forge-gui-mobile/src/forge/toolbox/GuiDialog.java index 890fbe3514f..bff40dabef7 100644 --- a/forge-gui-mobile/src/forge/toolbox/GuiDialog.java +++ b/forge-gui-mobile/src/forge/toolbox/GuiDialog.java @@ -24,18 +24,13 @@ public class GuiDialog { } public static void confirm(final Card c, final String question, final boolean defaultIsYes, final String[] options, final Callback callback) { - FThreads.invokeInEdtAndWait(new Runnable() { + final String title = c == null ? "Question" : c.getName() + " - Ability"; + String questionToUse = StringUtils.isBlank(question) ? "Activate card's ability?" : question; + String[] opts = options == null ? defaultConfirmOptions : options; + FOptionPane.showOptionDialog(questionToUse, title, FOptionPane.QUESTION_ICON, opts, defaultIsYes ? 0 : 1, new Callback() { @Override - public void run() { - final String title = c == null ? "Question" : c.getName() + " - Ability"; - String questionToUse = StringUtils.isBlank(question) ? "Activate card's ability?" : question; - String[] opts = options == null ? defaultConfirmOptions : options; - FOptionPane.showOptionDialog(questionToUse, title, FOptionPane.QUESTION_ICON, opts, defaultIsYes ? 0 : 1, new Callback() { - @Override - public void run(Integer result) { - callback.run(result == 0); - } - }); + public void run(Integer result) { + callback.run(result == 0); } }); } diff --git a/forge-gui-mobile/src/forge/toolbox/ListChooser.java b/forge-gui-mobile/src/forge/toolbox/ListChooser.java new file mode 100644 index 00000000000..42b211072bd --- /dev/null +++ b/forge-gui-mobile/src/forge/toolbox/ListChooser.java @@ -0,0 +1,228 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +package forge.toolbox; + +import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; +import com.google.common.base.Function; + +import forge.FThreads; +import forge.Forge.Graphics; +import forge.assets.FSkinColor; +import forge.assets.FSkinFont; +import forge.assets.FSkinColor.Colors; +import forge.toolbox.FList; +import forge.toolbox.FOptionPane; +import forge.util.Callback; +import forge.util.Utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * A simple class that shows a list of choices in a dialog. Two properties + * influence the behavior of a list chooser: minSelection and maxSelection. + * These two give the allowed number of selected items for the dialog to be + * closed. A negative value for minSelection suggests that the list is revealed + * and the choice doesn't matter. + *
    + *
  • If minSelection is 0, there will be a Cancel button.
  • + *
  • If minSelection is -1, 0 or 1, double-clicking a choice will also close the + * dialog.
  • + *
  • If the number of selections is out of bounds, the "OK" button is + * disabled.
  • + *
  • The dialog was "committed" if "OK" was clicked or a choice was double + * clicked.
  • + *
  • The dialog was "canceled" if "Cancel" or "X" was clicked.
  • + *
  • If the dialog was canceled, the selection will be empty.
  • + *
  • + *
+ * + * @param + * the generic type + * @author Forge + * @version $Id: ListChooser.java 25183 2014-03-14 23:09:45Z drdev $ + */ +public class ListChooser { + private static final FSkinColor BACK_COLOR = FSkinColor.get(Colors.CLR_ZEBRA); + private static final FSkinColor ALT_ITEM_COLOR = BACK_COLOR.getContrastColor(-20); + private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE); + private static final FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_BORDERS); + private static final float ITEM_HEIGHT = Utils.AVG_FINGER_HEIGHT * 0.8f; + + // Data and number of choices for the list + private int minChoices, maxChoices; + + // Flag: was the dialog already shown? + private boolean called; + + // initialized before; listeners may be added to it + private ChoiceList lstChoices; + private FOptionPane optionPane; + private final Callback> callback; + + public ListChooser(final String title, final int minChoices0, final int maxChoices0, final Collection list, final Function display, final Callback> callback0) { + FThreads.assertExecutedByEdt(true); + minChoices = minChoices0; + maxChoices = maxChoices0; + lstChoices = new ChoiceList(list); + callback = callback0; + + String[] options; + if (minChoices == 0) { + options = new String[] {"OK","Cancel"}; + } + else { + options = new String[] {"OK"}; + } + + if (maxChoices == 1 || minChoices == -1) { + lstChoices.allowMultipleSelections = false; + } + else { + lstChoices.allowMultipleSelections = true; + } + lstChoices.setHeight(ITEM_HEIGHT * Math.min(list.size(), 8)); //make tall enough to show 8 items without scrolling + + optionPane = new FOptionPane(null, title, null, lstChoices, options, minChoices < 0 ? 0 : -1, new Callback() { + @Override + public void run(Integer result) { + called = false; + if (result == 0) { + List choices = new ArrayList(); + for (int i : lstChoices.selectedIndices) { + choices.add(lstChoices.getItemValueAt(i)); + } + callback.run(choices); + } + else if (minChoices > 0) { + show(); //show if user tries to cancel when input is mandatory + } + else { + callback.run(new ArrayList()); + } + } + }); + } + + public void show() { + show(null); + } + + /** + * Shows the dialog and returns after the dialog was closed. + * + * @param index0 index to select when shown + * @return a boolean. + */ + public void show(final T item) { + if (called) { + throw new IllegalStateException("Already shown"); + } + called = true; + lstChoices.selectedIndices.clear(); + if (item == null) { + if (maxChoices > 0) { + lstChoices.selectedIndices.add(0); + } + } + else { + lstChoices.selectedIndices.add(lstChoices.getIndexOf(item)); + } + onSelectionChange(); + optionPane.show(); + } + + private void onSelectionChange() { + final int num = lstChoices.selectedIndices.size(); + optionPane.setButtonEnabled(0, (num >= minChoices) && (num <= maxChoices || maxChoices == -1)); + } + + public final class ChoiceList extends FList { + private boolean allowMultipleSelections; + private List selectedIndices = new ArrayList(); + + private ChoiceList(Collection items) { + super(items); + + setListItemRenderer(new ListItemRenderer() { + @Override + public float getItemHeight() { + return ITEM_HEIGHT; + } + + @Override + public boolean tap(T value, float x, float y, int count) { + int index = lstChoices.getIndexOf(value); + if (allowMultipleSelections) { + if (selectedIndices.contains(index)) { + selectedIndices.remove(index); + } + else { + selectedIndices.add(index); + } + } + else { + selectedIndices.clear(); + selectedIndices.add(index); + } + onSelectionChange(); + if (count == 2 && optionPane.isButtonEnabled(0)) { + optionPane.setResult(0); + } + return true; + } + + @Override + public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, float width, float height) { + float x = width * INSETS_FACTOR; + g.drawText(value.toString(), font, foreColor, x, 0, width - 2 * x, height, false, HAlignment.LEFT, true); + } + }); + setFontSize(12); + } + + @Override + protected void drawBackground(Graphics g) { + g.fillRect(BACK_COLOR, 0, 0, getWidth(), getHeight()); + } + + @Override + public void drawOverlay(Graphics g) { + g.drawRect(1.5f, BORDER_COLOR, 0, 0, getWidth(), getHeight()); + } + + @Override + protected FSkinColor getItemFillColor(ListItem item) { + int index = Math.round(item.getTop() / ITEM_HEIGHT); //more efficient indexing strategy + if (selectedIndices.contains(index)) { + return SEL_COLOR; + } + if (index % 2 == 1) { + return ALT_ITEM_COLOR; + } + return null; + } + + @Override + protected boolean drawLineSeparators() { + return false; + } + } +} diff --git a/forge-gui/src/main/java/forge/SGuiChoose.java b/forge-gui/src/main/java/forge/SGuiChoose.java index f6a912cf5d3..2235b3b240f 100644 --- a/forge-gui/src/main/java/forge/SGuiChoose.java +++ b/forge-gui/src/main/java/forge/SGuiChoose.java @@ -34,7 +34,7 @@ public class SGuiChoose { } final List choice = SGuiChoose.getChoices(message, 0, 1, choices); return choice.isEmpty() ? null : choice.get(0); - } // getChoiceOptional(String,T...) + } public static T oneOrNone(final String message, final Collection choices) { if ((choices == null) || choices.isEmpty()) { @@ -42,7 +42,7 @@ public class SGuiChoose { } final List choice = SGuiChoose.getChoices(message, 0, 1, choices); return choice.isEmpty() ? null : choice.get(0); - } // getChoiceOptional(String,T...) + } // returned Object will never be null /** @@ -208,7 +208,7 @@ public class SGuiChoose { } final List choice = SGuiChoose.sortedGetChoices(message, 0, 1, choices, comparer); return choice.isEmpty() ? null : choice.get(0); - } // getChoiceOptional(String,T...) + } // If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine public static T sortedOneOrNone(final String message, final List choices, Comparator comparer) { @@ -217,15 +217,14 @@ public class SGuiChoose { } final List choice = SGuiChoose.sortedGetChoices(message, 0, 1, choices, comparer); return choice.isEmpty() ? null : choice.get(0); - } // getChoiceOptional(String,T...) - + } // If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine public static T sortedOne(final String message, final T[] choices, Comparator comparer) { final List choice = SGuiChoose.sortedGetChoices(message, 1, 1, choices, comparer); assert choice.size() == 1; return choice.get(0); - } // getChoice() + } // If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine public static T sortedOne(final String message, final List choices, Comparator comparer) {