diff --git a/CHANGELOG.md b/CHANGELOG.md index 4681260..f895aaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 2.0.0 - 2024-04-28 + +### Added + +- Add a toggleable button for showing or hiding indirect mods. By default + indirect mods are not shown. Indirect mods are installed as child mods from a + top-level mod, and most of the time the setting screens are not relevant for + those. +- Add a search/filter widget to hide non-matching mods. This is useful when you + have a lot of mods installed. By typing a few characters, only mods with a + matching name or id will be shown. + ## 1.2.0 - 2024-04-28 ### Fixed diff --git a/src/main/java/se/icus/mag/modsettings/Main.java b/src/main/java/se/icus/mag/modsettings/Main.java index 573f866..03a2fd0 100644 --- a/src/main/java/se/icus/mag/modsettings/Main.java +++ b/src/main/java/se/icus/mag/modsettings/Main.java @@ -8,10 +8,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; -import se.icus.mag.modsettings.gui.ModSettingsScreen; +import se.icus.mag.modsettings.gui.screen.ModSettingsScreen; public class Main implements ClientModInitializer { public static final Logger LOGGER = LogManager.getLogger("modsettings"); + public static final Options OPTIONS = new Options(); @Override public void onInitializeClient() { @@ -25,4 +26,9 @@ public void onInitializeClient() { } }); } + + public static class Options { + public String filterText = ""; + public boolean showIndirect = false; + } } diff --git a/src/main/java/se/icus/mag/modsettings/ModRegistry.java b/src/main/java/se/icus/mag/modsettings/ModRegistry.java index 3919fb3..7a480f8 100644 --- a/src/main/java/se/icus/mag/modsettings/ModRegistry.java +++ b/src/main/java/se/icus/mag/modsettings/ModRegistry.java @@ -4,23 +4,27 @@ import com.terraformersmc.modmenu.api.ModMenuApi; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import net.fabricmc.loader.api.EntrypointException; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.entrypoint.EntrypointContainer; import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.client.gui.screen.Screen; -import org.apache.logging.log4j.Level; public class ModRegistry { private static final ModRegistry INSTANCE = new ModRegistry(); private final Map modNames = new HashMap<>(); + private final Map> modHierarchy = new HashMap<>(); + private final Map> configScreenFactories = new HashMap<>(); private final Map> overridingConfigScreenFactories = new HashMap<>(); @@ -33,6 +37,18 @@ public static ModRegistry getInstance() { /* This needs to be done att the right time of loading the mod, so cannot be done in the constructor. */ public void registerMods() { + for (ModContainer modContainer : FabricLoader.getInstance().getAllMods()) { + String modId = modContainer.getMetadata().getId(); + Optional parent = modContainer.getContainingMod(); + if (parent.isPresent()) { + String parentId = parent.get().getMetadata().getId(); + Set parentMod = modHierarchy.computeIfAbsent(parentId, k -> new HashSet<>()); + parentMod.add(modId); + } else { + modHierarchy.computeIfAbsent(modId, k -> new HashSet<>()); + } + } + List> modList = FabricLoader.getInstance().getEntrypointContainers("modmenu", Object.class); @@ -45,7 +61,7 @@ public void registerMods() { ModMenuApi modApi; if (unknownApi instanceof com.terraformersmc.modmenu.api.ModMenuApi modernApi) { - Main.LOGGER.log(Level.INFO,"Found configurable mod: " + modId + ", " + metadata.getName()); + Main.LOGGER.info("Found configurable mod: " + modId + ", " + metadata.getName()); modApi = modernApi; } else { Main.LOGGER.warn("Unknown Mod Menu API version for mod " + modId + ", class: " + unknownApi.getClass()); @@ -62,7 +78,7 @@ public void registerMods() { Optional container = FabricLoader.getInstance().getModContainer(overriddenModId); if (container.isPresent()) { String modName = container.get().getMetadata().getName(); - Main.LOGGER.log(Level.INFO, "Found overridden config for mod: " + overriddenModId + ", " + modName); + Main.LOGGER.info("Found overridden config for mod: " + overriddenModId + ", " + modName); modNames.put(overriddenModId, modName); } @@ -73,14 +89,30 @@ public void registerMods() { } } - public List getAllModIds() { + public Stream getAllModIds() { // Return mods sorted. This sorts on modID and not name, but is good enough. Comparator sorter = Comparator.comparing(modId -> modId.toLowerCase(Locale.ROOT)); // Fabric treats Vanilla ("minecraft") as a mod and returns the normal Options screen. // We don't want that so filter it out. return modNames.keySet().stream().sorted(sorter) - .filter(modId -> !modId.equals("minecraft")).collect(Collectors.toList()); + .filter(modId -> !modId.equals("minecraft")); + } + + public List getVisibleModIds(boolean showIndirect, String filterText) { + // If showIndirect is false, only include mods that is a parent. + return getAllModIds() + .filter(modId -> showIndirect || modHierarchy.containsKey(modId)) + .filter(modId -> filterText.isBlank() || modIdMatches(modId, filterText)) + .collect(Collectors.toList()); + } + + private boolean matches(String haystack, String needle) { + return haystack.toLowerCase(Locale.ROOT).contains(needle.toLowerCase(Locale.ROOT)); + } + + private boolean modIdMatches(String modId, String filter) { + return matches(modId, filter) || matches(getModName(modId), filter); } public String getModName(String modId) { diff --git a/src/main/java/se/icus/mag/modsettings/gui/MenuScreensChanger.java b/src/main/java/se/icus/mag/modsettings/gui/MenuScreensChanger.java index c46deea..f061955 100644 --- a/src/main/java/se/icus/mag/modsettings/gui/MenuScreensChanger.java +++ b/src/main/java/se/icus/mag/modsettings/gui/MenuScreensChanger.java @@ -6,6 +6,8 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ClickableWidget; import net.minecraft.text.Text; +import se.icus.mag.modsettings.gui.screen.ModSettingsScreen; +import se.icus.mag.modsettings.gui.widget.Button; public abstract class MenuScreensChanger { private static final int TITLE_FULL_BUTTON_WIDTH = 200; diff --git a/src/main/java/se/icus/mag/modsettings/gui/ModConfigInfo.java b/src/main/java/se/icus/mag/modsettings/gui/ModConfigInfo.java new file mode 100644 index 0000000..a33f2fb --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/ModConfigInfo.java @@ -0,0 +1,6 @@ +package se.icus.mag.modsettings.gui; + +import net.minecraft.client.gui.screen.Screen; + +public record ModConfigInfo(String modId, String modName, Screen configScreen) { +} diff --git a/src/main/java/se/icus/mag/modsettings/gui/ModSettingsScreen.java b/src/main/java/se/icus/mag/modsettings/gui/ModSettingsScreen.java deleted file mode 100644 index ddced57..0000000 --- a/src/main/java/se/icus/mag/modsettings/gui/ModSettingsScreen.java +++ /dev/null @@ -1,74 +0,0 @@ -package se.icus.mag.modsettings.gui; - -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.screen.ScreenTexts; -import net.minecraft.text.Text; -import se.icus.mag.modsettings.Main; -import se.icus.mag.modsettings.ModRegistry; - -import java.util.LinkedList; -import java.util.List; - -public class ModSettingsScreen extends Screen { - private static final int FULL_BUTTON_WIDTH = 200; - private static final int BUTTON_HEIGHT = 20; - private static final int TITLE_COLOR = 0xffffff; - - private final Screen previous; - private ModListWidget list; - private boolean initIsProcessing; - - public ModSettingsScreen(Screen previous) { - super(Text.translatable("modsettings.screen.title")); - this.previous = previous; - } - - @Override - protected void init() { - // Protect against mods like Content Creator Integration that triggers - // a recursive call of Screen.init() while creating the settings screen... - if (initIsProcessing) return; - initIsProcessing = true; - - // Put list between 32 pixels from top and bottom - this.list = new ModListWidget(this.client, this.width, this.height - 64, 32, 25); - this.list.addAll(getAllModConfigOptions()); - - this.addSelectableChild(this.list); - this.addDrawableChild(this.list); - this.addDrawableChild(new Button(this.width / 2 - FULL_BUTTON_WIDTH / 2, this.height - 27, - FULL_BUTTON_WIDTH, BUTTON_HEIGHT, ScreenTexts.DONE, - button -> this.client.setScreen(this.previous))); - initIsProcessing = false; - } - - private ModSettingsOption[] getAllModConfigOptions() { - List options = new LinkedList<>(); - for (String modId : ModRegistry.getInstance().getAllModIds()) { - try { - Screen configScreen = ModRegistry.getInstance().getConfigScreen(modId, this); - if (configScreen != null) { - options.add(new ModSettingsOption(modId, ModRegistry.getInstance().getModName(modId), configScreen)); - } - } catch (Throwable e) { - Main.LOGGER.error("Error creating Settings screen from mod " + modId, e); - } - } - return options.toArray(new ModSettingsOption[0]); - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); - context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 5, TITLE_COLOR); - } - - @Override - public void close() { - this.client.setScreen(this.previous); - } - - public record ModSettingsOption(String modId, String modName, Screen configScreen) { - } -} diff --git a/src/main/java/se/icus/mag/modsettings/gui/screen/ModSettingsScreen.java b/src/main/java/se/icus/mag/modsettings/gui/screen/ModSettingsScreen.java new file mode 100644 index 0000000..14cf778 --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/screen/ModSettingsScreen.java @@ -0,0 +1,92 @@ +package se.icus.mag.modsettings.gui.screen; + +import java.util.LinkedList; +import java.util.List; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import se.icus.mag.modsettings.Main; +import se.icus.mag.modsettings.ModRegistry; +import se.icus.mag.modsettings.gui.ModConfigInfo; +import se.icus.mag.modsettings.gui.widget.Button; +import se.icus.mag.modsettings.gui.widget.IconToggleButtonWidget; +import se.icus.mag.modsettings.gui.widget.ModListWidget; +import se.icus.mag.modsettings.gui.widget.SearchWidget; + +public class ModSettingsScreen extends TitledScreen { + private static final int FULL_BUTTON_WIDTH = 200; + private static final int BUTTON_HEIGHT = 20; + + private boolean initIsProcessing; + private ModListWidget list; + private SearchWidget searchWidget; + + public ModSettingsScreen(Screen previous) { + super(Text.translatable("modsettings.screen.title"), previous); + } + + @Override + protected void init() { + // Protect against mods like Content Creator Integration that triggers + // a recursive call of Screen.init() while creating the settings screen... + if (initIsProcessing) return; + initIsProcessing = true; + + // Add the toggle show indirect mods button + IconToggleButtonWidget showIndirectButton = new IconToggleButtonWidget(10, 6, + BUTTON_HEIGHT, BUTTON_HEIGHT, 15, 15, + List.of(new Identifier("modsettings", "expand"), + new Identifier("modsettings", "collapse")), + List.of(Tooltip.of(Text.translatable("modsettings.indirect.show")), + Tooltip.of(Text.translatable("modsettings.indirect.hide"))), + Main.OPTIONS.showIndirect ? 1 : 0, selection -> { + Main.OPTIONS.showIndirect = (selection == 1); + updateModButtons(); + }); + this.addDrawableChild(showIndirectButton); + + // Add the search widget + searchWidget = new SearchWidget(40, 6, 100, + Main.OPTIONS.filterText, this.textRenderer, text -> { + Main.OPTIONS.filterText = text; + updateModButtons(); + }, () -> this.setFocused(searchWidget)); + + this.addDrawableChild(searchWidget); + this.setInitialFocus(searchWidget); + + // Add the actual mod list buttons + // Put the list between 32 pixels from top and bottom + this.list = new ModListWidget(this.client, this.width, this.height - 64, 32, 25); + + this.addDrawableChild(this.list); + + // Add the Done button + this.addDrawableChild(new Button(this.width / 2 - FULL_BUTTON_WIDTH / 2, this.height - 27, FULL_BUTTON_WIDTH, BUTTON_HEIGHT, ScreenTexts.DONE, button -> this.client.setScreen(this.previous))); + + updateModButtons(); + initIsProcessing = false; + } + + private void updateModButtons() { + List visibleModIds = ModRegistry.getInstance().getVisibleModIds(Main.OPTIONS.showIndirect, Main.OPTIONS.filterText); + this.list.setModButtons(getModConfigInfo(visibleModIds)); + } + + private List getModConfigInfo(List modIds) { + List options = new LinkedList<>(); + for (String modId : modIds) { + try { + Screen configScreen = ModRegistry.getInstance().getConfigScreen(modId, this); + if (configScreen != null) { + options.add(new ModConfigInfo(modId, ModRegistry.getInstance().getModName(modId), configScreen)); + } + } catch (Throwable e) { + Main.LOGGER.error("Error creating Settings screen from mod " + modId, e); + } + } + return options; + } +} diff --git a/src/main/java/se/icus/mag/modsettings/gui/screen/TitledScreen.java b/src/main/java/se/icus/mag/modsettings/gui/screen/TitledScreen.java new file mode 100644 index 0000000..5984a38 --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/screen/TitledScreen.java @@ -0,0 +1,26 @@ +package se.icus.mag.modsettings.gui.screen; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +public class TitledScreen extends Screen { + private static final int TITLE_COLOR = 0xffffff; + protected final Screen previous; + + public TitledScreen(Text title, Screen previous) { + super(title); + this.previous = previous; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 5, TITLE_COLOR); + } + + @Override + public void close() { + this.client.setScreen(this.previous); + } +} diff --git a/src/main/java/se/icus/mag/modsettings/gui/Button.java b/src/main/java/se/icus/mag/modsettings/gui/widget/Button.java similarity index 87% rename from src/main/java/se/icus/mag/modsettings/gui/Button.java rename to src/main/java/se/icus/mag/modsettings/gui/widget/Button.java index fc1a312..14c6832 100644 --- a/src/main/java/se/icus/mag/modsettings/gui/Button.java +++ b/src/main/java/se/icus/mag/modsettings/gui/widget/Button.java @@ -1,4 +1,4 @@ -package se.icus.mag.modsettings.gui; +package se.icus.mag.modsettings.gui.widget; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.text.Text; diff --git a/src/main/java/se/icus/mag/modsettings/gui/widget/IconButtonWidget.java b/src/main/java/se/icus/mag/modsettings/gui/widget/IconButtonWidget.java new file mode 100644 index 0000000..84120ae --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/widget/IconButtonWidget.java @@ -0,0 +1,38 @@ +package se.icus.mag.modsettings.gui.widget; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class IconButtonWidget extends ButtonWidget { + private final int textureWidth; + private final int textureHeight; + protected Identifier texture; + + public IconButtonWidget(int x, int y, int width, int height,int textureWidth, int textureHeight, + Identifier texture, ButtonWidget.PressAction onPress) { + this(x, y, width, height, textureWidth, textureHeight, onPress); + this.texture = texture; + } + + protected IconButtonWidget(int x, int y, int width, int height,int textureWidth, int textureHeight, + ButtonWidget.PressAction onPress) { + super(x, y, width, height, Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER); + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + super.renderWidget(context, mouseX, mouseY, delta); + int x = this.getX() + this.getWidth() / 2 - this.textureWidth / 2; + int y = this.getY() + this.getHeight() / 2 - this.textureHeight / 2; + context.drawGuiTexture(this.texture, x, y, this.textureWidth, this.textureHeight); + } + + @Override + public void drawMessage(DrawContext context, TextRenderer textRenderer, int color) { + } +} diff --git a/src/main/java/se/icus/mag/modsettings/gui/widget/IconToggleButtonWidget.java b/src/main/java/se/icus/mag/modsettings/gui/widget/IconToggleButtonWidget.java new file mode 100644 index 0000000..d265264 --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/widget/IconToggleButtonWidget.java @@ -0,0 +1,42 @@ +package se.icus.mag.modsettings.gui.widget; + +import java.util.List; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.util.Identifier; + +public class IconToggleButtonWidget extends IconButtonWidget { + private final List textures; + private final List tooltips; + private final ToggleAction onChange; + + private int selection; + + public IconToggleButtonWidget(int x, int y, int width, int height, int textureWidth, int textureHeight, + List textures, List tooltips, int selection, ToggleAction onChange) { + super(x, y, width, height, textureWidth, textureHeight, ButtonWidget::onPress); + + this.textures = textures; + this.tooltips = tooltips; + this.onChange = onChange; + this.selection = selection; + updateSelection(); + } + + @Override + public void onPress() { + this.selection = (this.selection + 1) % this.textures.size(); + updateSelection(); + this.onChange.onChange(selection); + } + + private void updateSelection() { + this.texture = this.textures.get(this.selection); + this.setTooltip(this.tooltips.get(this.selection)); + } + + @FunctionalInterface + public interface ToggleAction { + void onChange(int selection); + } +} diff --git a/src/main/java/se/icus/mag/modsettings/gui/ModListWidget.java b/src/main/java/se/icus/mag/modsettings/gui/widget/ModListWidget.java similarity index 82% rename from src/main/java/se/icus/mag/modsettings/gui/ModListWidget.java rename to src/main/java/se/icus/mag/modsettings/gui/widget/ModListWidget.java index 96b1526..9672faa 100644 --- a/src/main/java/se/icus/mag/modsettings/gui/ModListWidget.java +++ b/src/main/java/se/icus/mag/modsettings/gui/widget/ModListWidget.java @@ -1,6 +1,7 @@ -package se.icus.mag.modsettings.gui; +package se.icus.mag.modsettings.gui.widget; import com.google.common.collect.ImmutableList; +import java.util.List; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; @@ -8,8 +9,7 @@ import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ElementListWidget; import net.minecraft.text.Text; - -import java.util.List; +import se.icus.mag.modsettings.gui.ModConfigInfo; public class ModListWidget extends ElementListWidget { private static final int BUTTON_HEIGHT = 20; @@ -29,16 +29,17 @@ protected int getScrollbarPositionX() { return super.getScrollbarPositionX() + 32; } - public void addAll(ModSettingsScreen.ModSettingsOption[] options) { - for (int i = 0; i < options.length; i += 2) { - addEntry(new ModEntry(options[i], i < options.length - 1 ? options[i + 1] : null)); + public void setModButtons(List options) { + clearEntries(); + for (int i = 0; i < options.size(); i += 2) { + addEntry(new ModEntry(options.get(i), i < options.size() - 1 ? options.get(i + 1) : null)); } } public class ModEntry extends Entry { final List buttons; - public ModEntry(ModSettingsScreen.ModSettingsOption mod1, ModSettingsScreen.ModSettingsOption mod2) { + public ModEntry(ModConfigInfo mod1, ModConfigInfo mod2) { ButtonWidget leftButton = new Button(ModListWidget.this.width / 2 - 155, 0, 150, BUTTON_HEIGHT, Text.of(mod1.modName()), button -> client.setScreen(mod1.configScreen())); if (mod2 != null) { @@ -69,6 +70,6 @@ public void render(DrawContext context, int index, int y, int x, int entryWidth, } } - public static abstract class Entry extends ElementListWidget.Entry { + public abstract static class Entry extends ElementListWidget.Entry { } } diff --git a/src/main/java/se/icus/mag/modsettings/gui/widget/SearchWidget.java b/src/main/java/se/icus/mag/modsettings/gui/widget/SearchWidget.java new file mode 100644 index 0000000..10e91b6 --- /dev/null +++ b/src/main/java/se/icus/mag/modsettings/gui/widget/SearchWidget.java @@ -0,0 +1,96 @@ +package se.icus.mag.modsettings.gui.widget; + +import java.util.List; +import java.util.function.Consumer; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.ContainerWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class SearchWidget extends ContainerWidget { + private static final int BUTTON_HEIGHT = 20; + + private final List children; + private final TextRenderer textRenderer; + private final Runnable requestFocus; + + private final TextFieldWidget textBox; + private boolean showTextBox; + + public SearchWidget(int x, int y, int width, String text, TextRenderer textRenderer, + Consumer changedListener, Runnable requestFocus) { + super(x, y, width, BUTTON_HEIGHT, Text.empty()); + + this.textRenderer = textRenderer; + this.requestFocus = requestFocus; + + IconButtonWidget searchButton = new IconButtonWidget(x, y, BUTTON_HEIGHT, BUTTON_HEIGHT, + 15, 15, new Identifier("modsettings", "search"), + b -> { + this.setText(""); + + this.showTextBox = !this.showTextBox; + updateTextBoxVisibility(); + }); + searchButton.setTooltip(Tooltip.of(Text.translatable("modsettings.search.tooltip"))); + + textBox = new TextFieldWidget(this.textRenderer, x + 26, y + 2, width - 26, 16, + Text.empty()); + textBox.setText(text); + textBox.setChangedListener(changedListener); + + this.showTextBox = !text.isEmpty(); + updateTextBoxVisibility(); + + children = List.of(searchButton, textBox); + } + + private void updateTextBoxVisibility() { + if (this.showTextBox) { + this.textBox.setVisible(true); + this.textBox.setFocusUnlocked(false); + this.textBox.setFocused(true); + this.requestFocus.run(); + } else { + this.textBox.setVisible(false); + this.textBox.setFocusUnlocked(true); + this.textBox.setFocused(false); + } + } + + @Override + public void setFocused(Element focused) { + // Force focus to textbox even if button was clicked + super.setFocused(textBox); + } + + @Override + public List children() { + return children; + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + children.forEach(c -> c.render(context, mouseX, mouseY, delta)); + } + + public String getText() { + return textBox.getText(); + } + + public void setText(String filterText) { + if (!filterText.equals(textBox.getText())) { + textBox.setText(filterText); + } + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + } +} diff --git a/src/main/resources/assets/modsettings/lang/en_us.json b/src/main/resources/assets/modsettings/lang/en_us.json index a0cb314..a6b36f4 100644 --- a/src/main/resources/assets/modsettings/lang/en_us.json +++ b/src/main/resources/assets/modsettings/lang/en_us.json @@ -2,5 +2,8 @@ "modsettings.screen.title": "Mod Settings", "modsettings.button.title": "Mod Settings...", "modsettings.key.open": "Open Mod Settings", - "modsettings.key.category": "Mod Settings" + "modsettings.key.category": "Mod Settings", + "modsettings.indirect.show": "Show all mods", + "modsettings.indirect.hide": "Hide indirect mods", + "modsettings.search.tooltip": "Search for mods" } diff --git a/src/main/resources/assets/modsettings/textures/gui/sprites/collapse.png b/src/main/resources/assets/modsettings/textures/gui/sprites/collapse.png new file mode 100644 index 0000000..bea4630 Binary files /dev/null and b/src/main/resources/assets/modsettings/textures/gui/sprites/collapse.png differ diff --git a/src/main/resources/assets/modsettings/textures/gui/sprites/expand.png b/src/main/resources/assets/modsettings/textures/gui/sprites/expand.png new file mode 100644 index 0000000..96118b3 Binary files /dev/null and b/src/main/resources/assets/modsettings/textures/gui/sprites/expand.png differ diff --git a/src/main/resources/assets/modsettings/textures/gui/sprites/search.png b/src/main/resources/assets/modsettings/textures/gui/sprites/search.png new file mode 100644 index 0000000..7521a56 Binary files /dev/null and b/src/main/resources/assets/modsettings/textures/gui/sprites/search.png differ diff --git a/src/main/textures/collapse.xcf b/src/main/textures/collapse.xcf new file mode 100644 index 0000000..922a0f1 Binary files /dev/null and b/src/main/textures/collapse.xcf differ diff --git a/src/main/textures/expand.xcf b/src/main/textures/expand.xcf new file mode 100644 index 0000000..7b294d6 Binary files /dev/null and b/src/main/textures/expand.xcf differ diff --git a/src/main/textures/search.xcf b/src/main/textures/search.xcf new file mode 100644 index 0000000..a2c0b3d Binary files /dev/null and b/src/main/textures/search.xcf differ