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.Forge;
|
||||||
import forge.assets.FSkinImage;
|
import forge.assets.FSkinImage;
|
||||||
|
import forge.assets.TextRenderer;
|
||||||
import forge.interfaces.IButton;
|
import forge.interfaces.IButton;
|
||||||
import forge.item.InventoryItem;
|
import forge.item.InventoryItem;
|
||||||
import forge.itemmanager.AdvancedSearch;
|
import forge.itemmanager.AdvancedSearch;
|
||||||
import forge.itemmanager.ItemManager;
|
import forge.itemmanager.ItemManager;
|
||||||
|
import forge.itemmanager.AdvancedSearch.IFilterControl;
|
||||||
import forge.menu.FMenuItem;
|
import forge.menu.FMenuItem;
|
||||||
import forge.menu.FPopupMenu;
|
import forge.menu.FPopupMenu;
|
||||||
import forge.menu.FTooltip;
|
import forge.menu.FTooltip;
|
||||||
@@ -81,6 +83,15 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
|
|||||||
label.setSize(width, height);
|
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 class FiltersLabel extends FLabel {
|
||||||
private String toolTipText;
|
private String toolTipText;
|
||||||
|
|
||||||
@@ -103,13 +114,24 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
|
|||||||
FPopupMenu menu = new FPopupMenu() {
|
FPopupMenu menu = new FPopupMenu() {
|
||||||
@Override
|
@Override
|
||||||
protected void buildMenu() {
|
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
|
@Override
|
||||||
public void handleEvent(FEvent e) {
|
public void handleEvent(FEvent e) {
|
||||||
edit();
|
edit();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
addItem(new FMenuItem("Clear Advanced Search", FSkinImage.DELETE, new FEventHandler() {
|
addItem(new FMenuItem("Remove Filter", FSkinImage.DELETE, new FEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(FEvent e) {
|
public void handleEvent(FEvent e) {
|
||||||
reset();
|
reset();
|
||||||
@@ -161,9 +183,7 @@ public class AdvancedSearchFilter<T extends InventoryItem> extends ItemFilter<T>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(Callback<Boolean> canCloseCallback) {
|
public void onClose(Callback<Boolean> canCloseCallback) {
|
||||||
//update expression when screen closed
|
onFilterChange.run();
|
||||||
model.updateExpression();
|
|
||||||
itemManager.applyNewOrModifiedFilter(AdvancedSearchFilter.this);
|
|
||||||
super.onClose(canCloseCallback);
|
super.onClose(canCloseCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import forge.UiCommand;
|
|||||||
import forge.assets.FImage;
|
import forge.assets.FImage;
|
||||||
import forge.assets.FSkinColor;
|
import forge.assets.FSkinColor;
|
||||||
import forge.assets.FSkinFont;
|
import forge.assets.FSkinFont;
|
||||||
|
import forge.assets.TextRenderer;
|
||||||
import forge.assets.FSkinColor.Colors;
|
import forge.assets.FSkinColor.Colors;
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.interfaces.IButton;
|
import forge.interfaces.IButton;
|
||||||
@@ -36,6 +37,7 @@ public class FMenuItem extends FDisplayObject implements IButton {
|
|||||||
private final FEventHandler handler;
|
private final FEventHandler handler;
|
||||||
private boolean pressed, allowForIcon, selected, tabMode;
|
private boolean pressed, allowForIcon, selected, tabMode;
|
||||||
private float textWidth;
|
private float textWidth;
|
||||||
|
private TextRenderer textRenderer;
|
||||||
|
|
||||||
public FMenuItem(String text0, FEventHandler handler0) {
|
public FMenuItem(String text0, FEventHandler handler0) {
|
||||||
this(text0, null, handler0, true);
|
this(text0, null, handler0, true);
|
||||||
@@ -71,6 +73,10 @@ public class FMenuItem extends FDisplayObject implements IButton {
|
|||||||
tabMode = tabMode0;
|
tabMode = tabMode0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTextRenderer(TextRenderer textRenderer0) {
|
||||||
|
textRenderer = textRenderer0;
|
||||||
|
}
|
||||||
|
|
||||||
public float getMinWidth() {
|
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
|
//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;
|
float width = textWidth + DIVOT_WIDTH + 4 * GAP_X;
|
||||||
@@ -128,7 +134,12 @@ public class FMenuItem extends FDisplayObject implements IButton {
|
|||||||
x += ICON_SIZE + GAP_X;
|
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
|
//draw separator line
|
||||||
if (tabMode) {
|
if (tabMode) {
|
||||||
|
|||||||
@@ -837,21 +837,26 @@ public class AdvancedSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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) {
|
||||||
//build list of filter options based on ItemManager type
|
final FilterOption option;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final FilterOption defaultOption = editFilter == null ? null : editFilter.option;
|
final FilterOption defaultOption = editFilter == null ? null : editFilter.option;
|
||||||
final FilterOption option = SGuiChoose.oneOrNone("Select a filter type", options, defaultOption, null);
|
if (defaultOption == null || reselectOption) {
|
||||||
if (option == null) { return 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)"
|
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> {
|
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<Object> expression = new ArrayList<Object>();
|
||||||
private final List<IFilterControl<T>> controls = new ArrayList<IFilterControl<T>>();
|
private final List<IFilterControl<T>> controls = new ArrayList<IFilterControl<T>>();
|
||||||
private IButton label;
|
private IButton label;
|
||||||
@@ -1002,42 +1009,16 @@ public class AdvancedSearch {
|
|||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public void addFilterControl(final IFilterControl<T> control) {
|
public void addFilterControl(final IFilterControl<T> control) {
|
||||||
final String emptyFilterText = "Select Filter...";
|
control.getBtnFilter().setText(EMPTY_FILTER_TEXT);
|
||||||
control.getBtnFilter().setText(emptyFilterText);
|
|
||||||
control.getBtnFilter().setCommand(new UiCommand() {
|
control.getBtnFilter().setCommand(new UiCommand() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
editFilterControl(control, null);
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
controls.add(control);
|
controls.add(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeFilterControl(IFilterControl<T> control) {
|
public void removeFilterControl(IFilterControl<T> control) {
|
||||||
int index = controls.indexOf(control);
|
int index = controls.indexOf(control);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
@@ -1048,6 +1029,43 @@ public class AdvancedSearch {
|
|||||||
controls.remove(index);
|
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) {
|
public void setLabel(IButton label0) {
|
||||||
label = label0;
|
label = label0;
|
||||||
updateLabel();
|
updateLabel();
|
||||||
|
|||||||
Reference in New Issue
Block a user