mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Support editing individual filters via menu
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
g.drawText(text, FONT, FORE_COLOR, x, 0, w - x - GAP_X, h, false, HAlignment.LEFT, true);
|
||||
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) {
|
||||
|
||||
@@ -837,21 +837,26 @@ public class AdvancedSearch {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends InventoryItem> Filter<T> getFilter(Class<? super T> type, Filter<T> editFilter) {
|
||||
//build list of filter options based on ItemManager type
|
||||
List<FilterOption> options = new ArrayList<FilterOption>();
|
||||
if (editFilter != null) {
|
||||
options.add(FilterOption.NONE); //provide option to clear existing filter
|
||||
}
|
||||
for (FilterOption opt : FilterOption.values()) {
|
||||
if (opt.type == type) {
|
||||
options.add(opt);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
final FilterOption option = SGuiChoose.oneOrNone("Select a filter type", options, defaultOption, null);
|
||||
if (option == null) { return editFilter; }
|
||||
if (defaultOption == null || reselectOption) {
|
||||
//build list of filter options based on ItemManager type
|
||||
List<FilterOption> options = new ArrayList<FilterOption>();
|
||||
if (editFilter != null) {
|
||||
options.add(FilterOption.NONE); //provide option to clear existing filter
|
||||
}
|
||||
for (FilterOption opt : FilterOption.values()) {
|
||||
if (opt.type == type) {
|
||||
options.add(opt);
|
||||
}
|
||||
}
|
||||
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,42 +1009,16 @@ 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() {
|
||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Filter<T> filter = getFilter(control.getGenericType(), control.getFilter());
|
||||
if (control.getFilter() != filter) {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
control.setFilter(filter);
|
||||
if (filter != null) {
|
||||
control.getBtnFilter().setText(GuiBase.getInterface().encodeSymbols(filter.toString(), false));
|
||||
}
|
||||
else {
|
||||
control.getBtnFilter().setText(emptyFilterText);
|
||||
}
|
||||
if (filter.getOption() == FilterOption.CARD_KEYWORDS) {
|
||||
//the first time the user selects keywords, preload keywords for all cards
|
||||
Runnable preloadTask = Keyword.getPreloadTask();
|
||||
if (preloadTask != null) {
|
||||
GuiBase.getInterface().runBackgroundTask("Loading keywords...", preloadTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
editFilterControl(control, null);
|
||||
}
|
||||
});
|
||||
controls.add(control);
|
||||
}
|
||||
|
||||
public void removeFilterControl(IFilterControl<T> control) {
|
||||
int index = controls.indexOf(control);
|
||||
if (index > 0) {
|
||||
@@ -1048,6 +1029,43 @@ public class AdvancedSearch {
|
||||
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(), onChange == null); //reselect option if no change handler passed
|
||||
if (control.getFilter() != filter) {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
control.setFilter(filter);
|
||||
if (filter != null) {
|
||||
control.getBtnFilter().setText(GuiBase.getInterface().encodeSymbols(filter.toString(), false));
|
||||
}
|
||||
else {
|
||||
control.getBtnFilter().setText(EMPTY_FILTER_TEXT);
|
||||
}
|
||||
if (filter.getOption() == FilterOption.CARD_KEYWORDS) {
|
||||
//the first time the user selects keywords, preload keywords for all cards
|
||||
Runnable preloadTask = Keyword.getPreloadTask();
|
||||
if (preloadTask != null) {
|
||||
GuiBase.getInterface().runBackgroundTask("Loading keywords...", preloadTask);
|
||||
}
|
||||
}
|
||||
if (onChange != null) {
|
||||
onChange.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Iterable<IFilterControl<T>> getControls() {
|
||||
return controls;
|
||||
}
|
||||
|
||||
public void setLabel(IButton label0) {
|
||||
label = label0;
|
||||
updateLabel();
|
||||
|
||||
Reference in New Issue
Block a user