From 1381bd6d9babec1b701b2e74918c5f885e51b709 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 18 Feb 2023 21:01:31 +0800 Subject: Close #669 --- .../rei/impl/client/config/ConfigManagerImpl.java | 57 ++-- .../rei/impl/client/config/ConfigObjectImpl.java | 46 ++- .../config/entries/ConfigureCategoriesScreen.java | 330 +++++++++++++++++++++ .../config/entries/FilteringCategoriesEntry.java | 112 ------- .../config/entries/FilteringCategoriesScreen.java | 251 ---------------- .../config/entries/NoFilteringCategoriesEntry.java | 102 ------- .../collapsible/CollapsibleEntriesScreen.java | 2 +- .../registry/category/CategoryRegistryImpl.java | 3 + .../shedaniel/rei/impl/client/view/ViewsImpl.java | 6 +- 9 files changed, 410 insertions(+), 499 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigureCategoriesScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java index 681356a99..6e871212b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java @@ -148,18 +148,6 @@ public class ConfigManagerImpl implements ConfigManager { Collections.singletonList(new FilteringEntry(220, value, ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules, defaultValue, saveConsumer, list -> ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules = Lists.newArrayList(list))); } , (field) -> field.getType() == List.class, ConfigObjectImpl.UseFilteringScreen.class); - guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> { - Map, Boolean> value = Utils., Boolean>>getUnsafely(field, config, new HashMap<>()); - Map, Boolean> defaultValue = Utils.getUnsafely(field, defaults); - Consumer, Boolean>> saveConsumer = (newValue) -> { - setUnsafely(field, config, newValue); - }; - return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? - Collections.singletonList(new NoFilteringCategoriesEntry(Component.translatable(i13n), value, defaultValue, saveConsumer)) - : - Collections.singletonList(new FilteringCategoriesEntry(Component.translatable(i13n), value, defaultValue, saveConsumer)); - } - , (field) -> field.getType() == Map.class, ConfigObjectImpl.UseFilteringCategoriesScreen.class); InternalLogger.getInstance().info("Config loaded"); saveConfig(); FavoritesConfigManager.getInstance().syncFrom(this); @@ -431,7 +419,12 @@ public class ConfigManagerImpl implements ConfigManager { builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.functionality")).getEntries().add(0, new ButtonsConfigEntry(220, Triple.of(new TranslatableComponent("text.rei.collapsible.entries"), $ -> {}, editedSink -> { Minecraft.getInstance().setScreen(new CollapsibleEntriesScreen(Minecraft.getInstance().screen, collapsibleConfigObject, editedSink)); - })).withSaveRunnable(() -> { + })) { + @Override + public boolean isEditable() { + return !(REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null); + } + }.withSaveRunnable(() -> { CollapsibleConfigManager.CollapsibleConfigObject actualConfig = CollapsibleConfigManager.getInstance().getConfig(); actualConfig.disabledGroups.clear(); actualConfig.disabledGroups.addAll(collapsibleConfigObject.disabledGroups); @@ -440,6 +433,26 @@ public class ConfigManagerImpl implements ConfigManager { CollapsibleConfigManager.getInstance().saveConfig(); ((CollapsibleEntryRegistryImpl) CollapsibleEntryRegistry.getInstance()).recollectCustomEntries(); })); + ConfigureCategoriesScreen filteringScreen = new ConfigureCategoriesScreen( + new HashMap<>(getConfig().getFilteringQuickCraftCategories()), + new HashSet<>(getConfig().getHiddenCategories()), + new ArrayList<>(getConfig().getCategoryOrdering()) + ); + builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.functionality")).getEntries().add(0, new ButtonsConfigEntry(220, + Triple.of(new TranslatableComponent("config.roughlyenoughitems.configureCategories"), $ -> {}, editedSink -> { + filteringScreen.parent = Minecraft.getInstance().screen; + filteringScreen.editedSink = editedSink; + Minecraft.getInstance().setScreen(filteringScreen); + })) { + @Override + public boolean isEditable() { + return !(REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null); + } + }.withSaveRunnable(() -> { + getConfig().setFilteringQuickCraftCategories(filteringScreen.getFilteringQuickCraftCategories()); + getConfig().setHiddenCategories(filteringScreen.getHiddenCategories()); + getConfig().setCategoryOrdering(filteringScreen.getCategoryOrdering()); + })); builder.getOrCreateCategory(Component.translatable("config.roughlyenoughitems.advanced")).getEntries().add(0, feedbackEntry); builder.getOrCreateCategory(Component.translatable("config.roughlyenoughitems.advanced")).getEntries().add(0, new ButtonsConfigEntry(220, Triple.of(new TranslatableComponent("text.rei.reload_config"), $ -> {}, $ -> { @@ -474,18 +487,18 @@ public class ConfigManagerImpl implements ConfigManager { TextListEntry supportText = ConfigEntryBuilder.create().startTextDescription( Component.translatable("text.rei.support.me.desc", Component.translatable("text.rei.support.me.patreon") - .withStyle(style -> style - .withColor(TextColor.fromRgb(0xff1fc3ff)) - .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://patreon.com/shedaniel")) + .withStyle(style -> style + .withColor(TextColor.fromRgb(0xff1fc3ff)) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://patreon.com/shedaniel")) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("https://patreon.com/shedaniel"))) - ), + ), Component.translatable("text.rei.support.me.bisect") - .withStyle(style -> style - .withColor(TextColor.fromRgb(0xff1fc3ff)) - .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.bisecthosting.com/shedaniel")) + .withStyle(style -> style + .withColor(TextColor.fromRgb(0xff1fc3ff)) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.bisecthosting.com/shedaniel")) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("https://www.bisecthosting.com/shedaniel"))) - ) - ) + ) + ) .withStyle(ChatFormatting.GRAY) ).build(); builder.getOrCreateCategory(Component.translatable("config.roughlyenoughitems.basics")).getEntries().add(0, new EmptyEntry(4)); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java index cd173f9c5..e79892688 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java @@ -52,10 +52,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @ApiStatus.Internal @Config(name = "roughlyenoughitems/config") @@ -452,7 +449,34 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @ApiStatus.Experimental @Override public Map, Boolean> getFilteringQuickCraftCategories() { - return advanced.filtering.filteringQuickCraftCategories; + return advanced.miscellaneous.categorySettings.filteringQuickCraftCategories; + } + + @ApiStatus.Internal + public void setFilteringQuickCraftCategories(Map, Boolean> filteringQuickCraftCategories) { + advanced.miscellaneous.categorySettings.filteringQuickCraftCategories = filteringQuickCraftCategories; + } + + @ApiStatus.Experimental + @Override + public Set> getHiddenCategories() { + return advanced.miscellaneous.categorySettings.hiddenCategories; + } + + @ApiStatus.Internal + public void setHiddenCategories(Set> hiddenCategories) { + advanced.miscellaneous.categorySettings.hiddenCategories = hiddenCategories; + } + + @ApiStatus.Experimental + @Override + public List> getCategoryOrdering() { + return advanced.miscellaneous.categorySettings.categoryOrdering; + } + + @ApiStatus.Internal + public void setCategoryOrdering(List> categoryOrdering) { + advanced.miscellaneous.categorySettings.categoryOrdering = categoryOrdering; } @Override @@ -588,10 +612,6 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Target({ElementType.FIELD}) @interface UseFilteringScreen {} - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.FIELD}) - @interface UseFilteringCategoriesScreen {} - @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) @interface UsePercentage { @@ -747,13 +767,19 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @ConfigEntry.Gui.PrefixText private boolean cachingFastEntryRendering = false; private boolean cachingDisplayLookup = true; + @ConfigEntry.Gui.Excluded public CategorySettings categorySettings = new CategorySettings(); + + public static class CategorySettings { + public Map, Boolean> filteringQuickCraftCategories = new HashMap<>(); + public List> categoryOrdering = new ArrayList<>(); + public Set> hiddenCategories = new HashSet<>(); + } } public static class Filtering { @UseFilteringScreen private List> filteredStacks = new ArrayList<>(); public boolean shouldFilterDisplays = true; @ConfigEntry.Gui.Excluded public List> filteringRules = new ArrayList<>(); - @UseFilteringCategoriesScreen public Map, Boolean> filteringQuickCraftCategories = new HashMap<>(); } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigureCategoriesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigureCategoriesScreen.java new file mode 100644 index 000000000..6818fa940 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigureCategoriesScreen.java @@ -0,0 +1,330 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.client.config.entries; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Label; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; + +import java.util.*; + +public class ConfigureCategoriesScreen extends Screen { + private final Map, Boolean> filteringQuickCraftCategories; + private final Set> hiddenCategories; + private final List> categoryOrdering; + private ListWidget listWidget; + public Runnable editedSink = () -> {}; + public Screen parent; + + public ConfigureCategoriesScreen(Map, Boolean> filteringQuickCraftCategories, Set> hiddenCategories, List> categoryOrdering) { + super(new TranslatableComponent("config.roughlyenoughitems.configureCategories.title")); + this.filteringQuickCraftCategories = filteringQuickCraftCategories; + this.hiddenCategories = hiddenCategories; + this.categoryOrdering = categoryOrdering; + for (CategoryRegistry.CategoryConfiguration configuration : CategoryRegistry.getInstance()) { + if (!this.categoryOrdering.contains(configuration.getCategoryIdentifier())) { + this.categoryOrdering.add(configuration.getCategoryIdentifier()); + } + } + } + + public Map, Boolean> getFilteringQuickCraftCategories() { + return filteringQuickCraftCategories; + } + + public Set> getHiddenCategories() { + return hiddenCategories; + } + + public List> getCategoryOrdering() { + return categoryOrdering; + } + + @Override + public void init() { + super.init(); + { + Component backText = Component.literal("↩ ").append(Component.translatable("gui.back")); + addRenderableWidget(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> { + minecraft.setScreen(parent); + this.parent = null; + })); + } + listWidget = addWidget(new ListWidget(minecraft, width, height, 30, height, BACKGROUND_LOCATION)); + this.resetListEntries(); + } + + public void resetListEntries() { + listWidget.children().clear(); + List> configurations = new ArrayList<>(CategoryRegistry.getInstance().stream().toList()); + configurations.sort(Comparator.comparingInt(o -> { + int indexOf = categoryOrdering.indexOf(o.getCategoryIdentifier()); + return indexOf == -1 ? Integer.MAX_VALUE : indexOf; + })); + for (CategoryRegistry.CategoryConfiguration configuration : configurations) { + listWidget.addItem(new DefaultListEntry(configuration)); + } + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + this.listWidget.render(matrices, mouseX, mouseY, delta); + super.render(matrices, mouseX, mouseY, delta); + this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1); + } + + @Override + public void onClose() { + this.minecraft.setScreen(parent); + } + + private static class ListWidget extends DynamicElementListWidget { + private boolean inFocus; + + public ListWidget(Minecraft client, int width, int height, int top, int bottom, ResourceLocation backgroundLocation) { + super(client, width, height, top, bottom, backgroundLocation); + } + + @Override + public boolean changeFocus(boolean lookForwards) { + if (!this.inFocus && this.getItemCount() == 0) { + return false; + } else { + this.inFocus = !this.inFocus; + if (this.inFocus && this.getSelectedItem() == null && this.getItemCount() > 0) { + this.moveSelection(1); + } else if (this.inFocus && this.getSelectedItem() != null) { + this.getSelectedItem(); + } + + return this.inFocus; + } + } + + @Override + protected boolean isSelected(int index) { + return false; + } + + @Override + public ListEntry getSelectedItem() { + return null; + } + + @Override + protected int addItem(ListEntry item) { + return super.addItem(item); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) + return true; + ListEntry item = getItemAtPosition(mouseX, mouseY); + if (item != null) { + client.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + selectItem(item); + this.setFocused(item); + this.setDragging(true); + return true; + } + return false; + } + + @Override + public int getItemWidth() { + return width - 40; + } + + @Override + protected int getScrollbarPosition() { + return width - 14; + } + } + + private static abstract class ListEntry extends DynamicElementListWidget.ElementEntry { + @Override + public int getItemHeight() { + return 45; + } + + @Override + public boolean changeFocus(boolean lookForwards) { + return false; + } + } + + private class DefaultListEntry extends ListEntry { + private final Label visibilityToggleButton, quickCraftToggleButton; + private final Button upButton, downButton; + private final CategoryRegistry.CategoryConfiguration configuration; + + public DefaultListEntry(CategoryRegistry.CategoryConfiguration configuration) { + this.configuration = configuration; + { + Component toggleText = Component.translatable("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure.toggle"); + visibilityToggleButton = Widgets.createClickableLabel(new Point(), toggleText, $ -> { + boolean enabled = !hiddenCategories.contains(configuration.getCategoryIdentifier()); + if (enabled) { + // set to false + hiddenCategories.add(configuration.getCategoryIdentifier()); + } else { + // set to true + hiddenCategories.remove(configuration.getCategoryIdentifier()); + } + + editedSink.run(); + }).leftAligned(); + quickCraftToggleButton = Widgets.createClickableLabel(new Point(), toggleText, $ -> { + boolean quickCraftingEnabledByDefault = configuration.isQuickCraftingEnabledByDefault(); + boolean enabled = filteringQuickCraftCategories.getOrDefault(configuration.getCategoryIdentifier(), quickCraftingEnabledByDefault); + if (enabled) { + // set to false + if (!quickCraftingEnabledByDefault) { + filteringQuickCraftCategories.remove(configuration.getCategoryIdentifier()); + } else { + filteringQuickCraftCategories.put(configuration.getCategoryIdentifier(), false); + } + } else { + // set to true + if (quickCraftingEnabledByDefault) { + filteringQuickCraftCategories.remove(configuration.getCategoryIdentifier()); + } else { + filteringQuickCraftCategories.put(configuration.getCategoryIdentifier(), true); + } + } + + editedSink.run(); + }).leftAligned(); + } + { + this.upButton = new Button(0, 0, 20, 20, new TextComponent("↑"), button -> { + int index = categoryOrdering.indexOf(configuration.getCategoryIdentifier()); + if (index > 0) { + categoryOrdering.remove(index); + categoryOrdering.add(index - 1, configuration.getCategoryIdentifier()); + editedSink.run(); + resetListEntries(); + } + }); + this.downButton = new Button(0, 0, 20, 20, new TextComponent("↓"), button -> { + int index = categoryOrdering.indexOf(configuration.getCategoryIdentifier()); + if (index < categoryOrdering.size() - 1) { + categoryOrdering.remove(index); + categoryOrdering.add(index + 1, configuration.getCategoryIdentifier()); + editedSink.run(); + resetListEntries(); + } + }); + this.upButton.active = categoryOrdering.indexOf(configuration.getCategoryIdentifier()) > 0; + this.downButton.active = categoryOrdering.indexOf(configuration.getCategoryIdentifier()) < categoryOrdering.size() - 1; + } + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + if (y + entryHeight < 0 || y > height) { + return; + } + + Minecraft client = Minecraft.getInstance(); + matrices.pushPose(); + matrices.translate(0, 0, 100); + configuration.getCategory().getIcon().render(matrices, new Rectangle(x + 2, y, 16, 16), mouseY, mouseY, delta); + matrices.popPose(); + int xPos = x + 22; + { + Component title = configuration.getCategory().getTitle(); + int i = client.font.width(title); + if (i > entryWidth - 28) { + FormattedText titleTrimmed = FormattedText.composite(client.font.substrByWidth(title, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); + client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(titleTrimmed), x + 2, y + 1, 16777215); + } else { + client.font.drawShadow(matrices, title.getVisualOrderText(), xPos, y + 1, 16777215); + } + } + { + Component id = Component.literal(configuration.getCategoryIdentifier().toString()) + .withStyle(ChatFormatting.DARK_GRAY); + int i = client.font.width(id); + if (i > entryWidth - 28) { + FormattedText idTrimmed = FormattedText.composite(client.font.substrByWidth(id, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); + client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(idTrimmed), x + 2, y + 12, 8421504); + } else { + client.font.drawShadow(matrices, id.getVisualOrderText(), xPos, y + 12, 8421504); + } + } + boolean shown = !hiddenCategories.contains(configuration.getCategoryIdentifier()); + { + Component subtitle = new TranslatableComponent("config.roughlyenoughitems.configureCategories.visibility." + shown) + .withStyle(shown ? ChatFormatting.GREEN : ChatFormatting.RED); + int i = client.font.drawShadow(matrices, subtitle.getVisualOrderText(), xPos, y + 22, 8421504); + visibilityToggleButton.getPoint().setLocation(i + 3, y + 22); + visibilityToggleButton.render(matrices, mouseX, mouseY, delta); + } + if (shown) { + Component subtitle = new TranslatableComponent("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure." + filteringQuickCraftCategories.getOrDefault(configuration.getCategoryIdentifier(), configuration.isQuickCraftingEnabledByDefault())) + .withStyle(ChatFormatting.GRAY); + int i = client.font.drawShadow(matrices, subtitle.getVisualOrderText(), xPos, y + 32, 8421504); + quickCraftToggleButton.getPoint().setLocation(i + 3, y + 32); + quickCraftToggleButton.render(matrices, mouseX, mouseY, delta); + } else { + quickCraftToggleButton.getPoint().setLocation(-12390, -12390); + } + upButton.x = x + entryWidth - 20; + upButton.y = y + entryHeight / 2 - 21; + upButton.render(matrices, mouseX, mouseY, delta); + downButton.x = x + entryWidth - 20; + downButton.y = y + entryHeight / 2 + 1; + downButton.render(matrices, mouseX, mouseY, delta); + } + + @Override + public List children() { + return List.of(visibilityToggleButton, quickCraftToggleButton, upButton, downButton); + } + + @Override + public List narratables() { + return List.of(); + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java deleted file mode 100644 index bb8832057..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.shedaniel.rei.impl.client.config.entries; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; -import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.ApiStatus; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - -@ApiStatus.Internal -public class FilteringCategoriesEntry extends AbstractConfigListEntry, Boolean>> { - private Consumer, Boolean>> saveConsumer; - private Map, Boolean> defaultValue; - private Map, Boolean> configFiltered; - final FilteringCategoriesScreen filteringScreen = new FilteringCategoriesScreen(this); - boolean edited = false; - private final AbstractWidget buttonWidget = new Button(0, 0, 150, 20, Component.translatable("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure"), button -> { - filteringScreen.parent = Minecraft.getInstance().screen; - Minecraft.getInstance().setScreen(filteringScreen); - }); - private final List children = ImmutableList.of(buttonWidget); - - public FilteringCategoriesEntry(Component fieldName, Map, Boolean> configFiltered, Map, Boolean> defaultValue, Consumer, Boolean>> saveConsumer) { - super(fieldName, false); - this.configFiltered = configFiltered; - this.defaultValue = defaultValue; - this.saveConsumer = saveConsumer; - } - - @Override - public Map, Boolean> getValue() { - return configFiltered; - } - - @Override - public Optional, Boolean>> getDefaultValue() { - return Optional.ofNullable(defaultValue); - } - - @Override - public void save() { - saveConsumer.accept(getValue()); - this.edited = false; - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { - super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta); - Window window = Minecraft.getInstance().getWindow(); - this.buttonWidget.y = y; - - Component displayedFieldName = this.getDisplayedFieldName(); - if (Minecraft.getInstance().font.isBidirectional()) { - Minecraft.getInstance().font.drawShadow(matrices, displayedFieldName.getVisualOrderText(), (float) (window.getGuiScaledWidth() - x - Minecraft.getInstance().font.width(displayedFieldName)), (float) (y + 6), 16777215); - this.buttonWidget.x = x + 2; - } else { - Minecraft.getInstance().font.drawShadow(matrices, displayedFieldName.getVisualOrderText(), (float) x, (float) (y + 6), this.getPreferredTextColor()); - this.buttonWidget.x = x + entryWidth - 150; - } - - this.buttonWidget.render(matrices, mouseX, mouseY, delta); - } - - @Override - public List children() { - return children; - } - - @Override - public List narratables() { - return children; - } - - @Override - public boolean isEdited() { - return super.isEdited() || edited; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java deleted file mode 100644 index 5bb6a98a9..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.shedaniel.rei.impl.client.config.entries; - -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvents; - -import java.util.Collections; -import java.util.List; - -public class FilteringCategoriesScreen extends Screen { - private final FilteringCategoriesEntry entry; - private ListWidget listWidget; - Screen parent; - - public FilteringCategoriesScreen(FilteringCategoriesEntry entry) { - super(Component.translatable("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure.title")); - this.entry = entry; - } - - @Override - public void init() { - super.init(); - { - Component backText = Component.literal("↩ ").append(Component.translatable("gui.back")); - addRenderableWidget(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> { - minecraft.setScreen(parent); - this.parent = null; - })); - } - listWidget = addWidget(new ListWidget(minecraft, width, height, 30, height, BACKGROUND_LOCATION)); - for (CategoryRegistry.CategoryConfiguration configuration : CategoryRegistry.getInstance()) { - listWidget.addItem(new DefaultListEntry(configuration)); - } - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - this.listWidget.render(matrices, mouseX, mouseY, delta); - super.render(matrices, mouseX, mouseY, delta); - this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1); - } - - @Override - public void onClose() { - this.minecraft.setScreen(parent); - } - - private static class ListWidget extends DynamicElementListWidget { - private boolean inFocus; - - public ListWidget(Minecraft client, int width, int height, int top, int bottom, ResourceLocation backgroundLocation) { - super(client, width, height, top, bottom, backgroundLocation); - } - - @Override - public boolean changeFocus(boolean lookForwards) { - if (!this.inFocus && this.getItemCount() == 0) { - return false; - } else { - this.inFocus = !this.inFocus; - if (this.inFocus && this.getSelectedItem() == null && this.getItemCount() > 0) { - this.moveSelection(1); - } else if (this.inFocus && this.getSelectedItem() != null) { - this.getSelectedItem(); - } - - return this.inFocus; - } - } - - @Override - protected boolean isSelected(int index) { - return false; - } - - @Override - public ListEntry getSelectedItem() { - return null; - } - - @Override - protected int addItem(ListEntry item) { - return super.addItem(item); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) - return true; - ListEntry item = getItemAtPosition(mouseX, mouseY); - if (item != null) { - client.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - selectItem(item); - this.setFocused(item); - this.setDragging(true); - return true; - } - return false; - } - - @Override - public int getItemWidth() { - return width - 40; - } - - @Override - protected int getScrollbarPosition() { - return width - 14; - } - } - - private static abstract class ListEntry extends DynamicElementListWidget.ElementEntry { - @Override - public int getItemHeight() { - return 35; - } - - @Override - public boolean changeFocus(boolean lookForwards) { - return false; - } - } - - private class DefaultListEntry extends ListEntry { - private final Button toggleButton; - private final CategoryRegistry.CategoryConfiguration configuration; - - public DefaultListEntry(CategoryRegistry.CategoryConfiguration configuration) { - this.configuration = configuration; - { - Component toggleText = Component.translatable("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure.toggle"); - toggleButton = new Button(0, 0, Minecraft.getInstance().font.width(toggleText) + 10, 20, toggleText, button -> { - boolean quickCraftingEnabledByDefault = configuration.isQuickCraftingEnabledByDefault(); - boolean enabled = entry.getValue().getOrDefault(configuration.getCategoryIdentifier(), quickCraftingEnabledByDefault); - if (enabled) { - // set to false - if (!quickCraftingEnabledByDefault) { - entry.getValue().remove(configuration.getCategoryIdentifier()); - } else { - entry.getValue().put(configuration.getCategoryIdentifier(), false); - } - } else { - // set to true - if (quickCraftingEnabledByDefault) { - entry.getValue().remove(configuration.getCategoryIdentifier()); - } else { - entry.getValue().put(configuration.getCategoryIdentifier(), true); - } - } - - entry.edited = true; - }); - } - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { - if (y + entryHeight < 0 || y > height) { - return; - } - - Minecraft client = Minecraft.getInstance(); - matrices.pushPose(); - matrices.translate(0, 0, 100); - configuration.getCategory().getIcon().render(matrices, new Rectangle(x + 2, y + 5, 16, 16), mouseY, mouseY, delta); - matrices.popPose(); - int xPos = x + 22; - { - Component title = configuration.getCategory().getTitle(); - int i = client.font.width(title); - if (i > entryWidth - 28) { - FormattedText titleTrimmed = FormattedText.composite(client.font.substrByWidth(title, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); - client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(titleTrimmed), x + 2, y + 1, 16777215); - } else { - client.font.drawShadow(matrices, title.getVisualOrderText(), xPos, y + 1, 16777215); - } - } - { - Component subtitle = Component.translatable("config.roughlyenoughitems.filtering.filteringQuickCraftCategories.configure." + entry.getValue().getOrDefault(configuration.getCategoryIdentifier(), configuration.isQuickCraftingEnabledByDefault())) - .withStyle(ChatFormatting.GRAY); - int i = client.font.width(subtitle); - if (i > entryWidth - 28) { - FormattedText subtitleTrimmed = FormattedText.composite(client.font.substrByWidth(subtitle, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); - client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(subtitleTrimmed), x + 2, y + 12, 8421504); - } else { - client.font.drawShadow(matrices, subtitle.getVisualOrderText(), xPos, y + 12, 8421504); - } - } - { - Component id = Component.literal(configuration.getCategoryIdentifier().toString()) - .withStyle(ChatFormatting.DARK_GRAY); - int i = client.font.width(id); - if (i > entryWidth - 28) { - FormattedText idTrimmed = FormattedText.composite(client.font.substrByWidth(id, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); - client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(idTrimmed), x + 2, y + 22, 8421504); - } else { - client.font.drawShadow(matrices, id.getVisualOrderText(), xPos, y + 22, 8421504); - } - } - toggleButton.x = x + entryWidth - 6 - toggleButton.getWidth(); - toggleButton.y = y + 5; - toggleButton.render(matrices, mouseX, mouseY, delta); - } - - @Override - public List children() { - return Collections.singletonList(toggleButton); - } - - @Override - public List narratables() { - return Collections.singletonList(toggleButton); - } - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java deleted file mode 100644 index 79df1eac1..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.shedaniel.rei.impl.client.config.entries; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; -import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.ApiStatus; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - -@ApiStatus.Internal -public class NoFilteringCategoriesEntry extends AbstractConfigListEntry, Boolean>> { - private Consumer, Boolean>> saveConsumer; - private Map, Boolean> defaultValue; - private Map, Boolean> configFiltered; - private final AbstractWidget buttonWidget = new Button(0, 0, 150, 20, Component.translatable("config.roughlyenoughitems.filteredEntries.loadWorldFirst"), button -> {}); - private final List children = ImmutableList.of(buttonWidget); - - public NoFilteringCategoriesEntry(Component fieldName, Map, Boolean> configFiltered, Map, Boolean> defaultValue, Consumer, Boolean>> saveConsumer) { - super(fieldName, false); - this.configFiltered = configFiltered; - this.defaultValue = defaultValue; - this.saveConsumer = saveConsumer; - } - - @Override - public Map, Boolean> getValue() { - return configFiltered; - } - - @Override - public Optional, Boolean>> getDefaultValue() { - return Optional.ofNullable(defaultValue); - } - - @Override - public void save() { - saveConsumer.accept(getValue()); - } - - @Override - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { - super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta); - Window window = Minecraft.getInstance().getWindow(); - this.buttonWidget.active = false; - this.buttonWidget.y = y; - - Component displayedFieldName = this.getDisplayedFieldName(); - if (Minecraft.getInstance().font.isBidirectional()) { - Minecraft.getInstance().font.drawShadow(matrices, displayedFieldName.getVisualOrderText(), (float) (window.getGuiScaledWidth() - x - Minecraft.getInstance().font.width(displayedFieldName)), (float) (y + 6), 16777215); - this.buttonWidget.x = x + 2; - } else { - Minecraft.getInstance().font.drawShadow(matrices, displayedFieldName.getVisualOrderText(), (float) x, (float) (y + 6), this.getPreferredTextColor()); - this.buttonWidget.x = x + entryWidth - 150; - } - - this.buttonWidget.render(matrices, mouseX, mouseY, delta); - } - - @Override - public List children() { - return children; - } - - @Override - public List narratables() { - return children; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java index 52c2f2361..cb5ff971c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java @@ -47,7 +47,7 @@ public class CollapsibleEntriesScreen extends Screen { private boolean dirty = true; public CollapsibleEntriesScreen(Screen parent, CollapsibleConfigManager.CollapsibleConfigObject configObject, Runnable editedSink) { - super(new TranslatableComponent("text.rei.collapsible.entries")); + super(new TranslatableComponent("text.rei.collapsible.entries.title")); this.parent = parent; this.configObject = configObject; this.editedSink = editedSink; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java index 00f4084b7..806ad4211 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java @@ -25,6 +25,7 @@ package me.shedaniel.rei.impl.client.registry.category; import com.google.common.base.MoreObjects; import dev.architectury.event.EventResult; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.category.ButtonArea; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; @@ -58,6 +59,8 @@ public class CategoryRegistryImpl implements CategoryRegistry { this.categories.clear(); this.listeners.clear(); this.visibilityPredicates.clear(); + this.registerVisibilityPredicate(category -> ConfigObject.getInstance().getHiddenCategories().contains(category.getCategoryIdentifier()) + ? EventResult.interruptFalse() : EventResult.pass()); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java index c42594b3b..aebdbb6c1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java @@ -249,10 +249,14 @@ public class ViewsImpl implements Views { private static Map, List> sortDisplays(Map, List> unsorted) { Object2IntMap> categoryOrder = new Object2IntOpenHashMap<>(); categoryOrder.defaultReturnValue(Integer.MAX_VALUE); - int i = 0; + int i = 100000; for (CategoryRegistry.CategoryConfiguration configuration : CategoryRegistry.getInstance()) { categoryOrder.put(configuration.getCategoryIdentifier(), i++); } + i = 0; + for (CategoryIdentifier identifier : ConfigObject.getInstance().getCategoryOrdering()) { + categoryOrder.put(identifier, i++); + } Map, List> result = new TreeMap<>(Comparator.comparingInt(category -> categoryOrder.getInt(category.getCategoryIdentifier()))); result.putAll(unsorted); return result; -- cgit