From 12d411ea7f58ca62b4667194993e25cae2508672 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 13:26:56 +0800 Subject: Fix #1207 --- .../rei/impl/client/config/ConfigObjectImpl.java | 2 +- .../gui/screen/AbstractDisplayViewingScreen.java | 4 +- .../gui/screen/CompositeDisplayViewingScreen.java | 6 +- .../gui/screen/DefaultDisplayViewingScreen.java | 52 +++++-- .../impl/client/gui/widget/TabContainerWidget.java | 160 +++++++++++++-------- 5 files changed, 145 insertions(+), 79 deletions(-) (limited to 'runtime/src/main/java') 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 d59ece66c..a18d7aeab 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 @@ -684,7 +684,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Comment("Declares how the scrollbar in composite screen should act.") private boolean compositeScrollBarPermanent = false; private boolean toastDisplayedOnCopyIdentifier = true; @Comment("Declares whether REI should use compact tabs for categories.") private boolean useCompactTabs = true; - @Comment("Declares whether REI should use compact tab buttons for categories.") @ConfigEntry.Gui.Excluded private boolean useCompactTabButtons = false; + @Comment("Declares whether REI should use compact tab buttons for categories.") private boolean useCompactTabButtons = false; } public static class Search { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java index 28050a6e3..c3cca9e72 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java @@ -119,8 +119,8 @@ public abstract class AbstractDisplayViewingScreen extends Screen implements Dis this.categoryPages = -1; } - protected void initTabs() { - this.tabs.init(new Rectangle(bounds.x, bounds.y - 28, bounds.width, 28), categories, new IntValue() { + protected void initTabs(int width) { + this.tabs.init(new Rectangle(bounds.getCenterX() - width / 2, bounds.y - 28, width, 28), new Rectangle(bounds.getCenterX() - width / 2, bounds.y - 28, width, 28), categories, new IntValue() { @Override public void accept(int value) { AbstractDisplayViewingScreen.this.categoryPages = value; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java index 050b91e35..2839f4236 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java @@ -98,10 +98,6 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen @Override public void init() { super.init(); - boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs(); - boolean isCompactTabButtons = ConfigObject.getInstance().isUsingCompactTabButtons(); - int tabButtonsSize = isCompactTabButtons ? 10 : 16; - int tabSize = isCompactTabs ? 24 : 28; this.children().clear(); this.widgets.clear(); this.buttonList.clear(); @@ -114,7 +110,7 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen int guiHeight = Mth.clamp(category.getDisplayHeight() + 40, 166, largestHeight); this.bounds = new Rectangle(width / 2 - guiWidth / 2, height / 2 - guiHeight / 2, guiWidth, guiHeight); - this.initTabs(); + this.initTabs(this.bounds.width); this.widgets.addAll(this.tabs.widgets()); List workstations = CategoryRegistry.getInstance().get(category.getCategoryIdentifier()).getWorkstations(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java index bfbc4368e..ec70906e6 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java @@ -39,6 +39,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; import me.shedaniel.rei.api.client.gui.widgets.Button; import me.shedaniel.rei.api.client.gui.widgets.Panel; import me.shedaniel.rei.api.client.gui.widgets.Widget; @@ -72,20 +73,37 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; @ApiStatus.Internal public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { + private static final int INNER_PADDING_Y = 36; + private static final int OUTER_PADDING_TOP = 2; + private static final int OUTER_PADDING_BOTTOM = 2; + private static final int DISPLAY_GAP = 4; private final Map>> recipeBounds = Maps.newHashMap(); private List widgets = Lists.newArrayList(); public int page; @Nullable private Panel workingStationsBaseWidget; private Button recipeBack, recipeNext, categoryBack, categoryNext; + private final int bestWidthDisplay; public DefaultDisplayViewingScreen(Map, List> categoriesMap, @Nullable CategoryIdentifier category) { super(categoriesMap, category); this.bounds = new Rectangle(0, 0, 176, 150); + //noinspection RedundantCast + List list = CollectionUtils.mapAndFilter(categoriesMap.entrySet(), Objects::nonNull, entry -> ((Optional) CollectionUtils.mapAndMax(entry.getValue(), + display -> ((DisplayCategory) entry.getKey()).getDisplayWidth(display.provideInternalDisplay()), Comparator.naturalOrder())).orElse(null)); + list.sort(Comparator.naturalOrder()); + int mode = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet().stream() + .max(Map.Entry.comparingByValue()) + .map(Map.Entry::getKey) + .orElse(150); + int median = list.size() % 2 == 0 ? (list.get(list.size() / 2) + list.get(list.size() / 2 - 1)) / 2 : list.get(list.size() / 2); + this.bestWidthDisplay = (int) Math.round((mode * 0.5 + median * 1.5) / 2.0); } @Override @@ -130,24 +148,28 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { this.children().clear(); this.recipeBounds.clear(); this.widgets.clear(); - int largestHeight = Math.min(Math.max(height - 34 - 30, 100), ConfigObject.getInstance().getMaxRecipesPageHeight()); - int maxWidthDisplay = CollectionUtils.mapAndMax(getCurrentDisplayed(), display -> getCurrentCategory().getDisplayWidth(display.provideInternalDisplay()), Comparator.naturalOrder()).orElse(150); +// int maxWidthDisplay = CollectionUtils.mapAndMax(getCurrentDisplayed(), display -> getCurrentCategory().getDisplayWidth(display.provideInternalDisplay()), Comparator.naturalOrder()).orElse(150); +// int guiWidth = Math.max(maxWidthDisplay + 10 + 14 + 14, 190); + int guiWidth = Math.max(bestWidthDisplay + 10 + 14 + 14, 190); + this.tabs.initTabsSize(guiWidth); + + int topMargin = OUTER_PADDING_TOP + this.tabs.tabSize() - 2 + (categories.size() > this.tabs.tabsPerPage() ? 16 : 0); + int bottomMargin = OUTER_PADDING_BOTTOM + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.CENTER ? 22 : 0); + int largestHeight = Math.min(Math.max(height - topMargin - bottomMargin, 100), ConfigObject.getInstance().getMaxRecipesPageHeight()); int maxHeight = Math.min(largestHeight, CollectionUtils., Integer>mapAndMax(categories, - category -> (category.getDisplayHeight() + 4) * Math.max(1, Math.min(getRecipesPerPage(largestHeight, category) + 1, Math.max(categoryMap.get(category).size(), ConfigObject.getInstance().getMaxRecipePerPage()))) + 36, Comparator.naturalOrder()).orElse(66)); - int totalDisplayHeight = (getCurrentCategory().getDisplayHeight() + 4) * Math.max(1, getRecipesPerPage(maxHeight, getCurrentCategory()) + 1) + 36; - int guiWidth = Math.max(maxWidthDisplay + 10 + 14 + 14, 190); - this.bounds = new Rectangle(width / 2 - guiWidth / 2, height / 2 - maxHeight / 2, guiWidth, maxHeight); + category -> INNER_PADDING_Y + (category.getDisplayHeight() + DISPLAY_GAP) * Math.max(1, Math.min(getRecipesPerPage(largestHeight, category) + 1, Math.max(categoryMap.get(category).size(), ConfigObject.getInstance().getMaxRecipePerPage()))), Comparator.naturalOrder()).orElse(66)); + this.bounds = new Rectangle(width / 2 - guiWidth / 2, topMargin + (height - topMargin - bottomMargin) / 2 - maxHeight / 2, guiWidth, maxHeight); - this.initTabs(); + this.initTabs(guiWidth); this.widgets.addAll(this.tabs.widgets()); this.page = Mth.clamp(page, 0, getCurrentTotalPages() - 1); - this.widgets.add(categoryBack = Widgets.createButton(new Rectangle(bounds.getX() + 5, bounds.getY() + 5, 12, 12), Component.empty()) + this.widgets.add(categoryBack = Widgets.createButton(new Rectangle(bounds.getCenterX() - guiWidth / 2 + 5, bounds.getY() + 5, 12, 12), Component.empty()) .onClick(button -> previousCategory()).tooltipLine(Component.translatable("text.rei.previous_category"))); this.widgets.add(Widgets.createClickableLabel(new Point(bounds.getCenterX(), bounds.getY() + 7), getCurrentCategory().getTitle(), clickableLabelWidget -> { ViewSearchBuilder.builder().addAllCategories().open(); }).tooltip(Component.translatable("text.rei.view_all_categories"))); - this.widgets.add(categoryNext = Widgets.createButton(new Rectangle(bounds.getMaxX() - 17, bounds.getY() + 5, 12, 12), Component.literal("")) + this.widgets.add(categoryNext = Widgets.createButton(new Rectangle(bounds.getCenterX() + guiWidth / 2 - 17, bounds.getY() + 5, 12, 12), Component.literal("")) .onClick(button -> nextCategory()).tooltipLine(Component.translatable("text.rei.next_category"))); this.categoryBack.setEnabled(categories.size() > 1); this.categoryNext.setEnabled(categories.size() > 1); @@ -168,7 +190,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { matrices.popPose(); }), 0, 0, 1)); - this.widgets.add(recipeBack = Widgets.createButton(new Rectangle(bounds.getX() + 5, bounds.getY() + 19, 12, 12), Component.literal("")) + this.widgets.add(recipeBack = Widgets.createButton(new Rectangle(bounds.getCenterX() - guiWidth / 2 + 5, bounds.getY() + 19, 12, 12), Component.literal("")) .onClick(button -> { page--; if (page < 0) @@ -189,7 +211,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { label.setMessage(Component.literal(String.format("%d/%d", page + 1, getCurrentTotalPages()))); label.setClickable(getCurrentTotalPages() > 1); }).tooltipFunction(label -> label.isClickable() ? new Component[]{Component.translatable("text.rei.go_back_first_page"), Component.literal(" "), Component.translatable("text.rei.shift_click_to", Component.translatable("text.rei.choose_page")).withStyle(ChatFormatting.GRAY)} : null)); - this.widgets.add(recipeNext = Widgets.createButton(new Rectangle(bounds.getMaxX() - 17, bounds.getY() + 19, 12, 12), Component.literal("")) + this.widgets.add(recipeNext = Widgets.createButton(new Rectangle(bounds.getCenterX() + guiWidth / 2 - 17, bounds.getY() + 19, 12, 12), Component.literal("")) .onClick(button -> { page++; if (page >= getCurrentTotalPages()) @@ -202,8 +224,8 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { widgets = CollectionUtils.map(widgets, widget -> Widgets.withTranslate(widget, 0, 0, 10)); widgets.add(Widgets.withTranslate(new PanelWidget(bounds), 0, 0, 5)); widgets.add(Widgets.withTranslate(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - fill(matrices, bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, darkStripesColor.value().getColor()); - fill(matrices, bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 31, darkStripesColor.value().getColor()); + fill(matrices, bounds.getCenterX() - guiWidth / 2 + 17, bounds.y + 5, bounds.getCenterX() + guiWidth / 2 - 17, bounds.y + 17, darkStripesColor.value().getColor()); + fill(matrices, bounds.getCenterX() - guiWidth / 2 + 17, bounds.y + 19, bounds.getCenterX() + guiWidth / 2 - 17, bounds.y + 31, darkStripesColor.value().getColor()); }), 0, 0, 6)); initWorkstations(widgets); @@ -218,7 +240,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { final DisplaySpec display = currentDisplayed.get(i); final Supplier displaySupplier = display::provideInternalDisplay; int displayWidth = getCurrentCategory().getDisplayWidth(displaySupplier.get()); - final Rectangle displayBounds = new Rectangle(getBounds().getCenterX() - displayWidth / 2, getBounds().getCenterY() + 16 - displayHeight * (getRecipesPerPage() + 1) / 2 - 2 * (getRecipesPerPage() + 1) + displayHeight * i + 4 * i, displayWidth, displayHeight); + final Rectangle displayBounds = new Rectangle(getBounds().getCenterX() - displayWidth / 2, getBounds().getCenterY() + 16 - displayHeight * (getRecipesPerPage() + 1) / 2 - 2 * (getRecipesPerPage() + 1) + displayHeight * i + DISPLAY_GAP * i, displayWidth, displayHeight); List setupDisplay; try { setupDisplay = getCurrentCategoryView(display.provideInternalDisplay()).setupDisplay(display.provideInternalDisplay(), displayBounds); @@ -303,7 +325,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { if (category.getFixedDisplaysPerPage() > 0) return category.getFixedDisplaysPerPage() - 1; int height = category.getDisplayHeight(); - return Mth.clamp(Mth.floor(((double) totalHeight - 36) / ((double) height + 4)) - 1, 0, Math.min(ConfigObject.getInstance().getMaxRecipePerPage() - 1, category.getMaximumDisplaysPerPage() - 1)); + return Mth.clamp(Mth.floor(((double) totalHeight - INNER_PADDING_Y) / ((double) height + DISPLAY_GAP)) - 1, 0, Math.min(ConfigObject.getInstance().getMaxRecipePerPage() - 1, category.getMaximumDisplaysPerPage() - 1)); } private final ValueAnimator darkStripesColor = ValueAnimator.ofColor() diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java index 950328d84..e67248c7b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java @@ -23,30 +23,37 @@ package me.shedaniel.rei.impl.client.gui.widget; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; import dev.architectury.utils.value.IntValue; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.widgets.CloseableScissors; -import me.shedaniel.rei.api.client.gui.widgets.DelegateWidget; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; +import me.shedaniel.rei.impl.client.gui.InternalTextures; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.stream.Stream; public class TabContainerWidget extends GuiComponent { private final Rectangle bounds = new Rectangle(); private final List widgets = new ArrayList<>(); private final NumberAnimator scrollAnimator = ValueAnimator.ofDouble(); + private boolean isCompactTabs; + private boolean isCompactTabButtons; + private int tabSize; + private int tabButtonsSize; private int tabsPerPage = 5; public TabContainerWidget() { @@ -57,78 +64,106 @@ public class TabContainerWidget extends GuiComponent { } public void updateScroll(List> categories, int selectedCategory, long duration) { - boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs(); - int tabSize = isCompactTabs ? 24 : 28; - - double curr = scrollAnimator.doubleValue() % (tabSize * categories.size()); - double newValue1 = selectedCategory * tabSize + Math.floor(scrollAnimator.doubleValue() / (tabSize * categories.size())) * (tabSize * categories.size()); - double newValue2 = newValue1 - (tabSize * categories.size()); - double newValue3 = newValue1 + (tabSize * categories.size()); - - Stream.of(newValue1, newValue2, newValue3).min(Comparator.comparingDouble(value -> Math.abs(value - scrollAnimator.doubleValue()))).ifPresent(newValue -> { - scrollAnimator.setTo(newValue, duration); - }); + this.initTabsVariables(); + if (categories.size() <= tabsPerPage) { + scrollAnimator.setAs(0d); + } else if (selectedCategory < tabsPerPage / 2) { + scrollAnimator.setTo(0d, duration); + } else if (selectedCategory >= categories.size() - (int) Math.ceil(tabsPerPage / 2)) { + scrollAnimator.setTo((categories.size() - tabsPerPage) * tabSize, duration); + } else { + scrollAnimator.setTo((selectedCategory - (tabsPerPage - 1) / 2.0) * tabSize, duration); + } + } + + private void initTabsVariables() { + this.isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs(); + this.isCompactTabButtons = ConfigObject.getInstance().isUsingCompactTabButtons(); + this.tabSize = isCompactTabs ? 24 : 28; + this.tabButtonsSize = isCompactTabButtons ? 10 : 16; + } + + public void initTabsSize(int width) { + this.initTabsVariables(); + this.tabsPerPage = Mth.floor((width - 6) / tabSize); + if (this.tabsPerPage % 2 == 0) + this.tabsPerPage--; } - public void init(Rectangle bounds, List> categories, IntValue categoryPages, IntValue selectedCategory, Runnable reInit) { + public void init(Rectangle scissorsBounds, Rectangle bounds, List> categories, IntValue categoryPages, IntValue selectedCategory, Runnable reInit) { this.setBounds(bounds); this.widgets.clear(); - boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs(); - int tabSize = isCompactTabs ? 24 : 28; - this.tabsPerPage = Mth.floor((this.bounds.getWidth() - 10) / tabSize); + initTabsSize(bounds.width); if (categoryPages.getAsInt() == -1) { categoryPages.accept(Math.max(0, selectedCategory.getAsInt() / tabsPerPage())); } + if (categories.size() > tabsPerPage) { + Button tabLeft, tabRight; + this.widgets.add(tabLeft = Widgets.createButton(new Rectangle(bounds.x, bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), new TextComponent("")) + .onClick(button -> { + int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); + currentCategoryPage = Math.floorMod(currentCategoryPage - 1, categories.size() / tabsPerPage() + 1); + selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, + tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); + }) + .tooltipLine(new TranslatableComponent("text.rei.previous_page"))); + this.widgets.add(tabRight = Widgets.createButton(new Rectangle(bounds.x + bounds.width - tabButtonsSize - (isCompactTabButtons ? 0 : 1), bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), new TextComponent("")) + .onClick(button -> { + int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); + currentCategoryPage = Math.floorMod(currentCategoryPage + 1, categories.size() / tabsPerPage() + 1); + selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, + tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); + }) + .tooltipLine(new TranslatableComponent("text.rei.next_page"))); + + this.widgets.add(Widgets.withTranslate(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + Rectangle tabLeftBounds = tabLeft.getBounds(); + Rectangle tabRightBounds = tabRight.getBounds(); + if (isCompactTabButtons) { + matrices.pushPose(); + matrices.translate(0, 0.5, 0); + RenderSystem.setShaderTexture(0, InternalTextures.ARROW_LEFT_SMALL_TEXTURE); + blit(matrices, tabLeftBounds.x + 2, tabLeftBounds.y + 2, 0, 0, 6, 6, 6, 6); + RenderSystem.setShaderTexture(0, InternalTextures.ARROW_RIGHT_SMALL_TEXTURE); + blit(matrices, tabRightBounds.x + 2, tabRightBounds.y + 2, 0, 0, 6, 6, 6, 6); + matrices.popPose(); + } else { + RenderSystem.setShaderTexture(0, InternalTextures.ARROW_LEFT_TEXTURE); + blit(matrices, tabLeftBounds.x + 4, tabLeftBounds.y + 4, 0, 0, 8, 8, 8, 8); + RenderSystem.setShaderTexture(0, InternalTextures.ARROW_RIGHT_TEXTURE); + blit(matrices, tabRightBounds.x + 4, tabRightBounds.y + 4, 0, 0, 8, 8, 8, 8); + } + }), 0, 0, 1)); + } + this.widgets.add(new Widget() { @Override public void render(PoseStack poses, int mouseX, int mouseY, float delta) { scrollAnimator.update(delta); int absLeft = bounds.x + bounds.width / 2 - tabsPerPage() * tabSize / 2; + int absRight = bounds.x + bounds.width / 2 + tabsPerPage() * tabSize / 2; int left; if (categories.size() > tabsPerPage()) { - left = bounds.x + bounds.width / 2 - tabSize / 2 - (int) Math.round(scrollAnimator.doubleValue()); + left = bounds.x + bounds.width / 2 - Math.min(categories.size(), tabsPerPage()) * tabSize / 2 - (int) Math.round(scrollAnimator.doubleValue()); updateScroll(categories, selectedCategory.getAsInt(), 300); } else { left = bounds.x + bounds.width / 2 - categories.size() * tabSize / 2; } - int passed = 0; for (TabWidget tab : Widgets.walk(TabContainerWidget.this.widgets(), widget -> widget instanceof TabWidget)) { - if (categories.size() <= tabsPerPage()) { - tab.getBounds().x = left; - left += tabSize; - } else { - if (left > bounds.getMaxX()) { - while (left > bounds.getMaxX()) { - left -= tabSize * categories.size(); - } - tab.getBounds().x = left; - left += tabSize; - } else if (left + tabSize < bounds.x) { - while (left + tabSize < bounds.x) { - left += tabSize * categories.size(); - } - tab.getBounds().x = left; - left += tabSize; - } else { - tab.getBounds().x = left; - left += tabSize; - } - } - passed++; - - if (tab.getBounds().x > bounds.getMaxX() || tab.getBounds().getMaxX() < bounds.x) { - tab.getBounds().x = -1000; - } + tab.getBounds().x = left; + left += tabSize; - if (tab.getBounds().getCenterX() <= absLeft + 20) { - tab.opacity = 1 - (absLeft + 20 - tab.getBounds().getCenterX()) / 20f; - tab.opacity = (float) Math.pow(Mth.clamp(tab.opacity, 0, 1), 0.9); - } else if (tab.getBounds().getCenterX() >= absLeft + tabsPerPage() * tabSize - 20) { - tab.opacity = 1 - (tab.getBounds().getCenterX() - (absLeft + tabsPerPage() * tabSize - 20)) / 20f; - tab.opacity = (float) Math.pow(Mth.clamp(tab.opacity, 0, 1), 0.9); + if (tab.isSelected()) { + tab.opacity = 1; + } else if (tab.getBounds().getCenterX() <= absLeft) { + tab.opacity = 1 - (absLeft - tab.getBounds().getCenterX()) / 20f; + tab.opacity = (float) Math.pow(Mth.clamp(tab.opacity, 0, 1), 1.2); + } else if (tab.getBounds().getCenterX() >= absRight) { + tab.opacity = 1 - (tab.getBounds().getCenterX() - absRight) / 20f; + tab.opacity = (float) Math.pow(Mth.clamp(tab.opacity, 0, 1), 1.2); } else { tab.opacity = 1; } @@ -136,6 +171,11 @@ public class TabContainerWidget extends GuiComponent { if (tab.opacity < 0.1) { tab.opacity = 0; } + + if (tab.opacity == 0 || tab.getBounds().x > bounds.getMaxX() || tab.getBounds().getMaxX() < bounds.x) { + tab.getBounds().x = -1000; + tab.opacity = 0; + } } } @@ -184,7 +224,7 @@ public class TabContainerWidget extends GuiComponent { this.widgets.add(new DelegateWidget(tab) { @Override public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { - try (CloseableScissors scissors = Widget.scissor(poseStack, new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height + 4))) { + try (CloseableScissors scissors = Widget.scissor(poseStack, new Rectangle(scissorsBounds.x, scissorsBounds.y, scissorsBounds.width, scissorsBounds.height + 4))) { super.render(poseStack, mouseX, mouseY, delta); } } @@ -199,4 +239,12 @@ public class TabContainerWidget extends GuiComponent { public int tabsPerPage() { return tabsPerPage; } + + public int tabButtonsSize() { + return tabButtonsSize; + } + + public int tabSize() { + return tabSize; + } } -- cgit From 0314b503554bd87214efd0632b1f877d7b941073 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 14:34:09 +0800 Subject: Fix buttons not respecting exclusion zones --- .../me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java index df33587da..8d01c05b7 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java @@ -60,6 +60,7 @@ import me.shedaniel.rei.impl.client.gui.widget.entrylist.PaginatedEntryListWidge import me.shedaniel.rei.impl.client.gui.widget.entrylist.ScrolledEntryListWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; +import me.shedaniel.rei.impl.common.util.RectangleUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; @@ -275,7 +276,17 @@ public abstract class ScreenOverlayImpl extends ScreenOverlay { bounds.width = maxWidth; } - return bounds; + return avoidButtons(bounds); + } + + private static Rectangle avoidButtons(Rectangle bounds) { + int buttonsHeight = 2; + if (REIRuntime.getInstance().getContextualSearchFieldLocation() == SearchFieldLocation.TOP_SIDE) buttonsHeight += 24; + if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) buttonsHeight += 22; + Rectangle area = REIRuntime.getInstance().calculateEntryListArea(bounds).clone(); + area.height = buttonsHeight; + return RectangleUtils.excludeZones(bounds, ScreenRegistry.getInstance().exclusionZones().getExclusionZones(Minecraft.getInstance().screen).stream() + .filter(zone -> zone.intersects(area))); } public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { -- cgit From 7d18e7ed9db822639121831922b30cf824fe974c Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 14:46:44 +0800 Subject: Solve some z-fighting for auto crafting --- .../rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java | 2 +- .../rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java index 2839f4236..d1ffe0d59 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java @@ -160,7 +160,7 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen this.widgets.addAll(setupDisplay); Optional supplier = CategoryRegistry.getInstance().get(category.getCategoryIdentifier()).getPlusButtonArea(); if (supplier.isPresent() && supplier.get().get(recipeBounds) != null) - this.widgets.add(InternalWidgets.createAutoCraftingButtonWidget(recipeBounds, supplier.get().get(recipeBounds), Component.literal(supplier.get().getButtonText()), display::provideInternalDisplay, display::provideInternalDisplayIds, setupDisplay, category)); + this.widgets.add(Widgets.withTranslate(InternalWidgets.createAutoCraftingButtonWidget(recipeBounds, supplier.get().get(recipeBounds), Component.literal(supplier.get().getButtonText()), display::provideInternalDisplay, display::provideInternalDisplayIds, setupDisplay, category), 0, 0, 100)); int index = 0; for (DisplaySpec recipeDisplay : categoryMap.get(category)) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java index ec70906e6..09622099e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java @@ -261,7 +261,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen { this.recipeBounds.put(displayBounds, Pair.of(display, setupDisplay)); this.widgets.add(new DisplayCompositeWidget(display, setupDisplay, displayBounds)); if (plusButtonArea.isPresent()) { - this.widgets.add(InternalWidgets.createAutoCraftingButtonWidget(displayBounds, plusButtonArea.get().get(displayBounds), Component.literal(plusButtonArea.get().getButtonText()), displaySupplier, display::provideInternalDisplayIds, setupDisplay, getCurrentCategory())); + this.widgets.add(Widgets.withTranslate(InternalWidgets.createAutoCraftingButtonWidget(displayBounds, plusButtonArea.get().get(displayBounds), Component.literal(plusButtonArea.get().getButtonText()), displaySupplier, display::provideInternalDisplayIds, setupDisplay, getCurrentCategory()), 0, 0, 100)); } } } -- cgit From 15ccf3bde1c84595b92d0bdd275f31588ff6c9b1 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 15:46:45 +0800 Subject: Fix #835 --- .../rei/RoughlyEnoughItemsCoreClient.java | 41 +++++++++++++++++++++- .../rei/impl/client/gui/ScreenOverlayImpl.java | 1 - .../impl/client/gui/widget/ConfigButtonWidget.java | 2 +- .../gui/widget/CraftableFilterButtonWidget.java | 2 +- .../gui/widget/search/OverlaySearchField.java | 6 ++-- 5 files changed, 44 insertions(+), 8 deletions(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 01e4fc1fd..0c1b9f5cf 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -24,6 +24,8 @@ package me.shedaniel.rei; import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.serialization.DataResult; import dev.architectury.event.Event; import dev.architectury.event.EventFactory; @@ -394,14 +396,51 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.interruptFalse(); return EventResult.pass(); }); - ClientGuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> { + int[] rendered = {0}; + ClientGuiEvent.RENDER_PRE.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen)) + return EventResult.pass(); + rendered[0] = 0; + return EventResult.pass(); + }); + ClientGuiEvent.RENDER_CONTAINER_BACKGROUND.register((screen, matrices, mouseX, mouseY, delta) -> { if (shouldReturn(screen)) return; + rendered[0] = 1; resetFocused(screen); if (!(screen instanceof DisplayScreen)) { getOverlay().render(matrices, mouseX, mouseY, delta); } + resetFocused(screen); + }); + ClientGuiEvent.RENDER_CONTAINER_FOREGROUND.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen)) + return; + rendered[0] = 2; + resetFocused(screen); + PoseStack poseStack = RenderSystem.getModelViewStack(); + poseStack.pushPose(); + poseStack.translate(-screen.leftPos, -screen.topPos, 0.0); + RenderSystem.applyModelViewMatrix(); ((ScreenOverlayImpl) getOverlay()).lateRender(matrices, mouseX, mouseY, delta); + poseStack.popPose(); + RenderSystem.applyModelViewMatrix(); + resetFocused(screen); + }); + ClientGuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> { + if (shouldReturn(screen) || rendered[0] == 2) + return; + if (screen instanceof AbstractContainerScreen) { + InternalLogger.getInstance().warn("Screen " + screen.getClass().getName() + " did not render background and foreground! This might cause rendering issues!"); + } + resetFocused(screen); + if (rendered[0] == 0 && !(screen instanceof DisplayScreen)) { + getOverlay().render(matrices, mouseX, mouseY, delta); + } + rendered[0] = 1; + if (rendered[0] == 1) { + ((ScreenOverlayImpl) getOverlay()).lateRender(matrices, mouseX, mouseY, delta); + } resetFocused(screen); }); ClientScreenInputEvent.MOUSE_DRAGGED_PRE.register((minecraftClient, screen, mouseX1, mouseY1, button, mouseX2, mouseY2) -> { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java index 8d01c05b7..fe6abb1ba 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java @@ -291,7 +291,6 @@ public abstract class ScreenOverlayImpl extends ScreenOverlay { public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { if (REIRuntime.getInstance().isOverlayVisible() && hasSpace()) { - REIRuntimeImpl.getSearchField().laterRender(matrices, mouseX, mouseY, delta); for (Widget widget : widgets) { if (widget instanceof LateRenderable && widget != menuHolder.widget()) widget.render(matrices, mouseX, mouseY, delta); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java index b68708fc6..cf4a4703f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java @@ -92,7 +92,7 @@ public class ConfigButtonWidget { helper.blit(matrices, bounds.x + 3, bounds.y + 3, 0, 0, 14, 14); helper.setBlitOffset(helper.getBlitOffset() - 1); }); - return InternalWidgets.wrapLateRenderable(Widgets.concat(configButton, overlayWidget)); + return Widgets.concat(configButton, overlayWidget); } private static Collection menuEntries() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java index bef9eaa02..94bf01921 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java @@ -85,7 +85,7 @@ public class CraftableFilterButtonWidget { itemRenderer.renderGuiItem(icon, (int) vector.x(), (int) vector.y()); itemRenderer.blitOffset = 0.0F; }); - return InternalWidgets.wrapLateRenderable(Widgets.concat(filterButton, overlayWidget)); + return Widgets.concat(filterButton, overlayWidget); } private static Collection menuEntries() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java index 70dbfd321..3180c2b0b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java @@ -80,7 +80,7 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg public int keybindFocusKey = -1; public boolean isMain = true; protected Tuple lastClickedDetails = null; - private List history = Lists.newArrayListWithCapacity(100); + private final List history = Lists.newArrayListWithCapacity(100); private final NumberAnimator progress = ValueAnimator.ofDouble(); public OverlaySearchField(int x, int y, int width, int height) { @@ -254,8 +254,6 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg @Override protected void renderSuggestion(PoseStack matrices, int x, int y) { - matrices.pushPose(); - matrices.translate(0, 0, 400); int color; if (containsMouse(PointHelper.ofMouse()) || isFocused()) { color = 0xddeaeaea; @@ -263,7 +261,6 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg color = -6250336; } this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.getSuggestion(), this.getWidth()), x, y, color); - matrices.popPose(); } @Override @@ -365,5 +362,6 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + laterRender(matrices, mouseX, mouseY, delta); } } -- cgit From 8682a155eb680dad1fb709007ad5152ed3e8433b Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 15:56:53 +0800 Subject: Fix merge conflicts --- .../rei/impl/client/gui/widget/TabContainerWidget.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java index e67248c7b..bbf4eaf2c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabContainerWidget.java @@ -25,7 +25,6 @@ package me.shedaniel.rei.impl.client.gui.widget; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; import dev.architectury.utils.value.IntValue; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; @@ -34,13 +33,9 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.impl.client.gui.InternalTextures; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import java.util.ArrayList; @@ -102,22 +97,22 @@ public class TabContainerWidget extends GuiComponent { if (categories.size() > tabsPerPage) { Button tabLeft, tabRight; - this.widgets.add(tabLeft = Widgets.createButton(new Rectangle(bounds.x, bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), new TextComponent("")) + this.widgets.add(tabLeft = Widgets.createButton(new Rectangle(bounds.x, bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), Component.empty()) .onClick(button -> { int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); currentCategoryPage = Math.floorMod(currentCategoryPage - 1, categories.size() / tabsPerPage() + 1); selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); }) - .tooltipLine(new TranslatableComponent("text.rei.previous_page"))); - this.widgets.add(tabRight = Widgets.createButton(new Rectangle(bounds.x + bounds.width - tabButtonsSize - (isCompactTabButtons ? 0 : 1), bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), new TextComponent("")) + .tooltipLine(Component.translatable("text.rei.previous_page"))); + this.widgets.add(tabRight = Widgets.createButton(new Rectangle(bounds.x + bounds.width - tabButtonsSize - (isCompactTabButtons ? 0 : 1), bounds.getMaxY() - tabSize + 1 - tabButtonsSize, tabButtonsSize, tabButtonsSize), Component.empty()) .onClick(button -> { int currentCategoryPage = selectedCategory.getAsInt() / tabsPerPage(); currentCategoryPage = Math.floorMod(currentCategoryPage + 1, categories.size() / tabsPerPage() + 1); selectedCategory.accept(Mth.clamp(currentCategoryPage * tabsPerPage() + tabsPerPage() / 2, tabsPerPage() / 2, categories.size() - (int) Math.ceil(tabsPerPage() / 2.0))); }) - .tooltipLine(new TranslatableComponent("text.rei.next_page"))); + .tooltipLine(Component.translatable("text.rei.next_page"))); this.widgets.add(Widgets.withTranslate(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { Rectangle tabLeftBounds = tabLeft.getBounds(); -- cgit From 9c865aff50b8c49e89ee1a7d6319d52cdcdd229a Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 12 Nov 2022 13:26:56 +0800 Subject: Add filtering rule screen if there isn't one --- .../config/entries/FilteringRulesScreen.java | 50 ++++++++++++++++++++-- .../filtering/rules/SearchFilteringRuleType.java | 7 +-- 2 files changed, 50 insertions(+), 7 deletions(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java index a0d53ccd5..624ba0315 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java @@ -23,13 +23,22 @@ package me.shedaniel.rei.impl.client.config.entries; +import com.google.common.base.Suppliers; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; +import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextImpl; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringResultImpl; import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule; +import me.shedaniel.rei.impl.client.entry.filtering.rules.SearchFilteringRuleType; import me.shedaniel.rei.impl.client.gui.InternalTextures; +import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -42,9 +51,8 @@ import net.minecraft.network.chat.FormattedText; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; public class FilteringRulesScreen extends Screen { @@ -183,7 +191,7 @@ public class FilteringRulesScreen extends Screen { public DefaultRuleEntry(FilteringRule rule, FilteringEntry entry, Function screenFunction) { super(rule); - this.screenFunction = (screenFunction == null ? ((FilteringRuleType>) rule.getType()).createEntryScreen(rule) : screenFunction); + this.screenFunction = Objects.requireNonNullElseGet(screenFunction == null ? ((FilteringRuleType>) rule.getType()).createEntryScreen(rule) : screenFunction, () -> placeholderScreen(rule)); configureButton = new Button(0, 0, 20, 20, Component.nullToEmpty(null), button -> { entry.edited = true; Minecraft.getInstance().setScreen(this.screenFunction.apply(Minecraft.getInstance().screen)); @@ -249,4 +257,38 @@ public class FilteringRulesScreen extends Screen { return Arrays.asList(configureButton, deleteButton); } } + + private static Function placeholderScreen(FilteringRule r) { + class PlaceholderScreen extends FilteringRuleOptionsScreen> { + public PlaceholderScreen(Screen parent) { + super(r, parent); + } + + @Override + public void addEntries(Consumer entryConsumer) { + addEmpty(entryConsumer, 10); + Function function = bool -> { + return new TranslatableComponent("rule.roughlyenoughitems.filtering.search.show." + bool); + }; + FilteringContextImpl context = new FilteringContextImpl(EntryRegistry.getInstance().getEntryStacks().toList()); + rule.processFilteredStacks(context, () -> new FilteringResultImpl(new ArrayList<>(), new ArrayList<>()), + rule.prepareCache(false), false); + + entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(true), + Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, + Suppliers.ofInstance(CollectionUtils.map(context.getShownStacks(), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.normalize()))))))); + addEmpty(entryConsumer, 10); + entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(false), + Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, + Suppliers.ofInstance(CollectionUtils.map(context.getHiddenStacks(), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.normalize()))))))); + } + + @Override + public void save() { + } + } + return PlaceholderScreen::new; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java index ebea083b7..65cdf4508 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java @@ -26,6 +26,7 @@ package me.shedaniel.rei.impl.client.entry.filtering.rules; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.search.SearchFilter; @@ -118,7 +119,7 @@ public enum SearchFilteringRuleType implements FilteringRuleType function.apply(show == null ? rule.show : show.getBoolean()), - Collections.singletonList(new EntryStacksRuleEntry(rule, () -> entryStacks, entry, show)))); + Collections.singletonList(new EntryStacksRuleEntry(rule, () -> entryStacks)))); } @Override @@ -135,10 +136,10 @@ public enum SearchFilteringRuleType implements FilteringRuleType> entryStacks; + private final Supplier> entryStacks; private int totalHeight; - public EntryStacksRuleEntry(SearchFilteringRule rule, Supplier> entryStacks, FilteringRuleOptionsScreen.TextFieldRuleEntry entry, FilteringRuleOptionsScreen.BooleanRuleEntry show) { + public EntryStacksRuleEntry(FilteringRule rule, Supplier> entryStacks) { super(rule); this.entryStacks = entryStacks; } -- cgit From 2123544fcf3ad7ec6d89e671a993a75737e3a44e Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 27 Nov 2022 17:50:11 +0800 Subject: Make filtering more immediate --- .../config/entries/FilteringRulesScreen.java | 20 +- .../entry/filtering/FilteringContextImpl.java | 51 +++- .../filtering/rules/BasicFilteringRuleImpl.java | 199 ++++++++++----- .../impl/common/entry/type/EntryRegistryImpl.java | 73 +++--- .../impl/common/entry/type/EntryRegistryList.java | 13 +- .../common/entry/type/EntryRegistryListImpl.java | 206 ++++++++++++++++ .../common/entry/type/EntryRegistryListener.java | 6 +- .../impl/common/entry/type/FilteredEntryList.java | 43 ++++ .../rei/impl/common/entry/type/FilteringLogic.java | 107 +++++++++ .../common/entry/type/NormalEntryRegistryList.java | 115 --------- .../common/entry/type/PreFilteredEntryList.java | 266 +++++++++++++-------- .../entry/type/ReloadingEntryRegistryList.java | 107 --------- .../client/runtime/DefaultClientRuntimePlugin.java | 3 +- .../shedaniel/rei/plugin/test/REITestPlugin.java | 42 +++- 14 files changed, 812 insertions(+), 439 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryListImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/FilteredEntryList.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/FilteringLogic.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/NormalEntryRegistryList.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/ReloadingEntryRegistryList.java (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java index 624ba0315..6c6d4cceb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java @@ -33,12 +33,13 @@ import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextImpl; -import me.shedaniel.rei.impl.client.entry.filtering.FilteringResultImpl; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextType; import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule; import me.shedaniel.rei.impl.client.entry.filtering.rules.SearchFilteringRuleType; import me.shedaniel.rei.impl.client.gui.InternalTextures; import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; +import me.shedaniel.rei.impl.common.entry.type.FilteringLogic; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -54,6 +55,7 @@ import net.minecraft.sounds.SoundEvents; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Collectors; public class FilteringRulesScreen extends Screen { private final FilteringEntry entry; @@ -268,21 +270,19 @@ public class FilteringRulesScreen extends Screen { public void addEntries(Consumer entryConsumer) { addEmpty(entryConsumer, 10); Function function = bool -> { - return new TranslatableComponent("rule.roughlyenoughitems.filtering.search.show." + bool); + return Component.translatable("rule.roughlyenoughitems.filtering.search.show." + bool); }; - FilteringContextImpl context = new FilteringContextImpl(EntryRegistry.getInstance().getEntryStacks().toList()); - rule.processFilteredStacks(context, () -> new FilteringResultImpl(new ArrayList<>(), new ArrayList<>()), - rule.prepareCache(false), false); + Map> stacks = FilteringLogic.hidden(FilteringLogic.getRules(), false, false, EntryRegistry.getInstance().getEntryStacks().collect(Collectors.toList())); entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(true), Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, - Suppliers.ofInstance(CollectionUtils.map(context.getShownStacks(), - stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.normalize()))))))); + Suppliers.ofInstance(CollectionUtils.map(stacks.get(FilteringContextType.SHOWN), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.unwrap().normalize()))))))); addEmpty(entryConsumer, 10); entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(false), Collections.singletonList(new SearchFilteringRuleType.EntryStacksRuleEntry(rule, - Suppliers.ofInstance(CollectionUtils.map(context.getHiddenStacks(), - stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.normalize()))))))); + Suppliers.ofInstance(CollectionUtils.map(stacks.get(FilteringContextType.HIDDEN), + stack -> (EntryWidget) Widgets.createSlot(new Rectangle(0, 0, 18, 18)).disableBackground().entry(stack.unwrap().normalize()))))))); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java index d0e26a9fc..697bcde63 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java @@ -27,6 +27,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import it.unimi.dsi.fastutil.longs.*; import me.shedaniel.rei.api.client.entry.filtering.FilteringContext; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; @@ -69,20 +70,35 @@ public class FilteringContextImpl implements FilteringContext { @Override public Collection> getHiddenStacks() { - return getPublicFacing(FilteringContextType.HIDDEN); + return getStacksFacing(FilteringContextType.HIDDEN); } @Override public Collection> getShownStacks() { - return getPublicFacing(FilteringContextType.SHOWN); + return getStacksFacing(FilteringContextType.SHOWN); } @Override public Collection> getUnsetStacks() { - return getPublicFacing(FilteringContextType.DEFAULT); + return getStacksFacing(FilteringContextType.DEFAULT); } - private Collection> getPublicFacing(FilteringContextType type) { + @Override + public LongCollection getHiddenExactHashes() { + return getHashesFacing(FilteringContextType.HIDDEN); + } + + @Override + public LongCollection getShownExactHashes() { + return getHashesFacing(FilteringContextType.SHOWN); + } + + @Override + public LongCollection getUnsetExactHashes() { + return getHashesFacing(FilteringContextType.DEFAULT); + } + + private Collection> getStacksFacing(FilteringContextType type) { Set wrappers = this.stacks.get(type); if (wrappers == null || wrappers.isEmpty()) return List.of(); return new AbstractSet<>() { @@ -98,6 +114,33 @@ public class FilteringContextImpl implements FilteringContext { }; } + private LongCollection getHashesFacing(FilteringContextType type) { + Set wrappers = this.stacks.get(type); + if (wrappers == null || wrappers.isEmpty()) return LongSets.emptySet(); + return new Abstract