Support editing individual filters via menu

This commit is contained in:
drdev
2015-09-20 16:32:37 +00:00
parent b3ae6ef349
commit 22bfc9f1e3
3 changed files with 98 additions and 49 deletions

View File

@@ -5,10 +5,12 @@ import com.google.common.base.Predicate;
import forge.Forge;
import forge.assets.FSkinImage;
import forge.assets.TextRenderer;
import forge.interfaces.IButton;
import forge.item.InventoryItem;
import forge.itemmanager.AdvancedSearch;
import forge.itemmanager.ItemManager;
import forge.itemmanager.AdvancedSearch.IFilterControl;
import forge.menu.FMenuItem;
import forge.menu.FPopupMenu;
import forge.menu.FTooltip;
@@ -81,6 +83,15 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
label.setSize(width, height);
}
private final Runnable onFilterChange = new Runnable() {
@Override
public void run() {
//update expression when edit screen closed or a single filter is changed
model.updateExpression();
itemManager.applyNewOrModifiedFilter(AdvancedSearchFilter.this);
}
};
private class FiltersLabel extends FLabel {
private String toolTipText;
@@ -103,13 +114,24 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
FPopupMenu menu = new FPopupMenu() {
@Override
protected void buildMenu() {
addItem(new FMenuItem("Edit Advanced Search", FSkinImage.EDIT, new FEventHandler() {
//add a menu item for each filter to allow easily editing just that filter
for (final IFilterControl<T> control : model.getControls()) {
FMenuItem item = new FMenuItem(control.getFilter().toString(), FSkinImage.EDIT, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
model.editFilterControl(control, onFilterChange);
}
});
item.setTextRenderer(new TextRenderer()); //ensure symbols are displayed
addItem(item);
}
addItem(new FMenuItem("Edit Expression", FSkinImage.EDIT, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
edit();
}
}));
addItem(new FMenuItem("Clear Advanced Search", FSkinImage.DELETE, new FEventHandler() {
addItem(new FMenuItem("Remove Filter", FSkinImage.DELETE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
reset();
@@ -161,9 +183,7 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
@Override
public void onClose(Callback<Boolean> canCloseCallback) {
//update expression when screen closed
model.updateExpression();
itemManager.applyNewOrModifiedFilter(AdvancedSearchFilter.this);
onFilterChange.run();
super.onClose(canCloseCallback);
}

View File

@@ -9,6 +9,7 @@ import forge.UiCommand;
import forge.assets.FImage;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.TextRenderer;
import forge.assets.FSkinColor.Colors;
import forge.assets.FSkinProp;
import forge.interfaces.IButton;
@@ -36,6 +37,7 @@ public class FMenuItem extends FDisplayObject implements IButton {
private final FEventHandler handler;
private boolean pressed, allowForIcon, selected, tabMode;
private float textWidth;
private TextRenderer textRenderer;
public FMenuItem(String text0, FEventHandler handler0) {
this(text0, null, handler0, true);
@@ -71,6 +73,10 @@ public class FMenuItem extends FDisplayObject implements IButton {
tabMode = tabMode0;
}
public void setTextRenderer(TextRenderer textRenderer0) {
textRenderer = textRenderer0;
}
public float getMinWidth() {
//pretend there's a divot even if there isn't to provide extra right padding and allow menu items to line up nicer
float width = textWidth + DIVOT_WIDTH + 4 * GAP_X;
@@ -128,7 +134,12 @@ public class FMenuItem extends FDisplayObject implements IButton {
x += ICON_SIZE + GAP_X;
}
if (textRenderer == null) {
g.drawText(text, FONT, FORE_COLOR, x, 0, w - x - GAP_X, h, false, HAlignment.LEFT, true);
}
else {
textRenderer.drawText(g, text, FONT, FORE_COLOR, x, 0, w - x - GAP_X, h, 0, h, false, HAlignment.LEFT, true);
}
//draw separator line
if (tabMode) {

View File

@@ -837,7 +837,10 @@ public class AdvancedSearch {
}
@SuppressWarnings("unchecked")
public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type, Filter<T> editFilter) {
public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type, Filter<T> editFilter, boolean reselectOption) {
final FilterOption option;
final FilterOption defaultOption = editFilter == null ? null : editFilter.option;
if (defaultOption == null || reselectOption) {
//build list of filter options based on ItemManager type
List<FilterOption> options = new ArrayList<FilterOption>();
if (editFilter != null) {
@@ -848,10 +851,12 @@ public class AdvancedSearch {
options.add(opt);
}
}
final FilterOption defaultOption = editFilter == null ? null : editFilter.option;
final FilterOption option = SGuiChoose.oneOrNone("Select a filter type", options, defaultOption, null);
option = SGuiChoose.oneOrNone("Select a filter type", options, defaultOption, null);
if (option == null) { return editFilter; }
}
else {
option = defaultOption;
}
if (option == FilterOption.NONE) { return null; } //allow user to clear filter by selecting "(none)"
@@ -928,6 +933,8 @@ public class AdvancedSearch {
}
public static class Model<T extends InventoryItem> {
private static final String EMPTY_FILTER_TEXT = "Select Filter...";
private final List<Object> expression = new ArrayList<Object>();
private final List<IFilterControl<T>> controls = new ArrayList<IFilterControl<T>>();
private IButton label;
@@ -1002,15 +1009,31 @@ public class AdvancedSearch {
@SuppressWarnings("serial")
public void addFilterControl(final IFilterControl<T> control) {
final String emptyFilterText = "Select Filter...";
control.getBtnFilter().setText(emptyFilterText);
control.getBtnFilter().setText(EMPTY_FILTER_TEXT);
control.getBtnFilter().setCommand(new UiCommand() {
@Override
public void run() {
editFilterControl(control, null);
}
});
controls.add(control);
}
public void removeFilterControl(IFilterControl<T> control) {
int index = controls.indexOf(control);
if (index > 0) {
IFilterControl<T> prevControl = controls.get(index - 1);
prevControl.getBtnAnd().setSelected(control.getBtnAnd().isSelected());
prevControl.getBtnOr().setSelected(control.getBtnOr().isSelected());
}
controls.remove(index);
}
public void editFilterControl(final IFilterControl<T> control, final Runnable onChange) {
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
final Filter<T> filter = getFilter(control.getGenericType(), control.getFilter());
final Filter<T> filter = getFilter(control.getGenericType(), control.getFilter(), onChange == null); //reselect option if no change handler passed
if (control.getFilter() != filter) {
FThreads.invokeInEdtLater(new Runnable() {
@Override
@@ -1020,7 +1043,7 @@ public class AdvancedSearch {
control.getBtnFilter().setText(GuiBase.getInterface().encodeSymbols(filter.toString(), false));
}
else {
control.getBtnFilter().setText(emptyFilterText);
control.getBtnFilter().setText(EMPTY_FILTER_TEXT);
}
if (filter.getOption() == FilterOption.CARD_KEYWORDS) {
//the first time the user selects keywords, preload keywords for all cards
@@ -1029,23 +1052,18 @@ public class AdvancedSearch {
GuiBase.getInterface().runBackgroundTask("Loading keywords...", preloadTask);
}
}
if (onChange != null) {
onChange.run();
}
}
});
}
}
});
}
});
controls.add(control);
}
public void removeFilterControl(IFilterControl<T> control) {
int index = controls.indexOf(control);
if (index > 0) {
IFilterControl<T> prevControl = controls.get(index - 1);
prevControl.getBtnAnd().setSelected(control.getBtnAnd().isSelected());
prevControl.getBtnOr().setSelected(control.getBtnOr().isSelected());
}
controls.remove(index);
public Iterable<IFilterControl<T>> getControls() {
return controls;
}
public void setLabel(IButton label0) {