From b41ea249ad2af3c2d03bb269bf4eb7b03220fdb8 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Thu, 14 Apr 2022 12:50:23 +0800 Subject: Add what's getting hidden in the search filtering screen --- .../config/entries/FilteringRuleOptionsScreen.java | 122 +++++++++++++++++++++ .../entry/filtering/rules/SearchFilteringRule.java | 83 ++++++++++++-- 2 files changed, 198 insertions(+), 7 deletions(-) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java index 154c34445..fac731ecf 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java @@ -23,8 +23,12 @@ package me.shedaniel.rei.impl.client.config.entries; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +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.impl.client.entry.filtering.FilteringRule; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; @@ -32,16 +36,21 @@ import net.minecraft.client.gui.components.EditBox; 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.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; import net.minecraft.util.FormattedCharSequence; +import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; public abstract class FilteringRuleOptionsScreen> extends Screen { private final FilteringEntry entry; @@ -258,4 +267,117 @@ public abstract class FilteringRuleOptionsScreen> ext return Collections.singletonList(widget); } } + + public static class SubRulesEntry extends RuleEntry { + private static final ResourceLocation CONFIG_TEX = new ResourceLocation("cloth-config2", "textures/gui/cloth_config.png"); + private final CategoryLabelWidget widget; + private final List rules; + private final List children; + private boolean expanded; + private Supplier name; + + public SubRulesEntry(FilteringRule rule, Supplier name, List rules) { + super(rule); + this.rules = rules; + this.widget = new CategoryLabelWidget(); + this.name = name; + this.expanded = true; + this.children = new ArrayList<>(rules); + this.children.add(widget); + } + + public List getRules() { + return rules; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + RenderSystem.setShaderTexture(0, CONFIG_TEX); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + this.widget.rectangle.x = x + 3; + this.widget.rectangle.y = y; + this.widget.rectangle.width = entryWidth - 6; + this.widget.rectangle.height = 24; + this.blit(matrices, x + 3, y + 5, 24, (this.widget.rectangle.contains(mouseX, mouseY) ? 18 : 0) + (this.expanded ? 9 : 0), 9, 9); + Minecraft.getInstance().font.drawShadow(matrices, this.name.get().getVisualOrderText(), (float) x + 3 + 15, (float) (y + 6), this.widget.rectangle.contains(mouseX, mouseY) ? -1638890 : -1); + + for (RuleEntry performanceEntry : this.rules) { + performanceEntry.setParent(this.getParent()); + } + + if (this.expanded) { + int yy = y + 24; + + RuleEntry entry; + for (Iterator iterator = this.rules.iterator(); iterator.hasNext(); yy += entry.getItemHeight()) { + entry = iterator.next(); + entry.render(matrices, -1, yy, x + 3 + 15, entryWidth - 15 - 3, entry.getItemHeight(), mouseX, mouseY, isHovered && this.getFocused() == entry, delta); + } + } + } + + @Override + public int getMorePossibleHeight() { + if (!this.expanded) { + return -1; + } else { + List list = new ArrayList<>(); + int i = 24; + + for (RuleEntry entry : this.rules) { + i += entry.getItemHeight(); + if (entry.getMorePossibleHeight() >= 0) { + list.add(i + entry.getMorePossibleHeight()); + } + } + + list.add(i); + return list.stream().max(Integer::compare).orElse(0) - this.getItemHeight(); + } + } + + @Override + public int getItemHeight() { + if (!this.expanded) { + return 24; + } else { + int i = 24; + + RuleEntry entry; + for (Iterator iterator = this.rules.iterator(); iterator.hasNext(); i += entry.getItemHeight()) { + entry = iterator.next(); + } + + return i; + } + } + + @Override + public List children() { + return children; + } + + @Override + public List narratables() { + return Collections.emptyList(); + } + + public class CategoryLabelWidget implements GuiEventListener { + private final Rectangle rectangle = new Rectangle(); + + public CategoryLabelWidget() { + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.rectangle.contains(mouseX, mouseY)) { + SubRulesEntry.this.expanded = !SubRulesEntry.this.expanded; + Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + return true; + } else { + return false; + } + } + } + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java index 5f5969674..0e48f1b97 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java @@ -25,35 +25,49 @@ package me.shedaniel.rei.impl.client.entry.filtering.rules; import com.google.common.base.Suppliers; import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.config.entries.FilteringEntry; import me.shedaniel.rei.impl.client.config.entries.FilteringRuleOptionsScreen; +import me.shedaniel.rei.impl.client.config.entries.FilteringScreen; import me.shedaniel.rei.impl.client.entry.filtering.AbstractFilteringRule; import me.shedaniel.rei.impl.client.entry.filtering.FilteringCache; import me.shedaniel.rei.impl.client.entry.filtering.FilteringContext; import me.shedaniel.rei.impl.client.entry.filtering.FilteringResult; +import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; +import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +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.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.Mth; import net.minecraft.util.StringUtil; -import java.util.Collection; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static me.shedaniel.rei.impl.client.gui.widget.EntryListWidget.entrySize; @Environment(EnvType.CLIENT) public class SearchFilteringRule extends AbstractFilteringRule { @@ -115,7 +129,7 @@ public class SearchFilteringRule extends AbstractFilteringRule> stacks, List>>> completableFutures) { @@ -147,21 +161,34 @@ public class SearchFilteringRule extends AbstractFilteringRule new FilteringRuleOptionsScreen(entry, this, screen) { TextFieldRuleEntry entry = null; BooleanRuleEntry show = null; - + List entryStacks = new ArrayList<>(); + @Override public void addEntries(Consumer entryConsumer) { addEmpty(entryConsumer, 10); addText(entryConsumer, new TranslatableComponent("rule.roughlyenoughitems.filtering.search.filter").withStyle(ChatFormatting.GRAY)); entryConsumer.accept(entry = new TextFieldRuleEntry(width - 36, rule, widget -> { widget.setMaxLength(9999); + widget.setResponder(searchTerm -> { + SearchFilter filter = SearchProvider.getInstance().createFilter(searchTerm); + entryStacks = EntryRegistry.getInstance().getEntryStacks().parallel() + .filter(filter) + .map(EntryStack::normalize) + .map(stack -> new EntryWidget(new Rectangle(0, 0, 18,18)).noBackground().entry(stack)) + .collect(Collectors.toList()); + }); if (entry != null) widget.setValue(entry.getWidget().getValue()); else widget.setValue(rule.filterStr); })); addEmpty(entryConsumer, 10); addText(entryConsumer, new TranslatableComponent("rule.roughlyenoughitems.filtering.search.show").withStyle(ChatFormatting.GRAY)); - entryConsumer.accept(show = new BooleanRuleEntry(width - 36, show == null ? rule.show : show.getBoolean(), rule, bool -> { + Function function = bool -> { return new TranslatableComponent("rule.roughlyenoughitems.filtering.search.show." + bool); - })); + }; + entryConsumer.accept(show = new BooleanRuleEntry(width - 36, show == null ? rule.show : show.getBoolean(), rule, function)); + addEmpty(entryConsumer, 10); + entryConsumer.accept(new SubRulesEntry(rule, () -> function.apply(show == null ? rule.show : show.getBoolean()), + Collections.singletonList(new EntryStacksRuleEntry(rule, () -> entryStacks, entry, show)))); } @Override @@ -171,4 +198,46 @@ public class SearchFilteringRule extends AbstractFilteringRule> entryStacks; + private int totalHeight; + + public EntryStacksRuleEntry(SearchFilteringRule rule, Supplier> entryStacks, FilteringRuleOptionsScreen.TextFieldRuleEntry entry, FilteringRuleOptionsScreen.BooleanRuleEntry show) { + super(rule); + this.entryStacks = entryStacks; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + BatchedEntryRendererManager manager = new BatchedEntryRendererManager(); + int entrySize = entrySize(); + int width = entryWidth / entrySize; + int i = 0; + for (EntryWidget stack : entryStacks.get()) { + stack.getBounds().setLocation(x + (i % width) * entrySize, y + (i / width) * entrySize); + if (stack.getBounds().getMaxY() >= 0 && stack.getBounds().getY() <= Minecraft.getInstance().getWindow().getGuiScaledHeight()) { + manager.add(stack); + } + i++; + } + manager.render(matrices, mouseX, mouseY, delta); + totalHeight = (i / width + 1) * entrySize; + } + + @Override + public int getItemHeight() { + return totalHeight; + } + + @Override + public List narratables() { + return Lists.newArrayList(); + } + + @Override + public List children() { + return Lists.newArrayList(); + } + } } -- cgit From 8d9d53b65561fedea8f61d194d411565fd89b57e Mon Sep 17 00:00:00 2001 From: shedaniel Date: Fri, 15 Apr 2022 13:18:08 +0800 Subject: Fix #817 --- .../shedaniel/rei/plugin/common/DefaultPlugin.java | 9 ++- .../plugin/common/fabric/DefaultPluginImpl.java | 65 ++++++++++++++++++++++ .../resources/roughlyenoughitems.accessWidener | 1 - .../rei/plugin/common/forge/DefaultPluginImpl.java | 6 ++ .../main/resources/META-INF/accesstransformer.cfg | 1 - 5 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 fabric/src/main/java/me/shedaniel/rei/plugin/common/fabric/DefaultPluginImpl.java diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java index 74adb6305..5ba026cc5 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java @@ -88,7 +88,7 @@ public class DefaultPlugin implements BuiltinPlugin, REIServerPlugin { ItemStack stack = entry.getValue(); Item item = stack.getItem(); if (item instanceof BucketItem bucketItem) { - Fluid fluid = bucketItem.content; + Fluid fluid = getFluidFromBucket(bucketItem); if (fluid != null) { return CompoundEventResult.interruptTrue(Stream.of(EntryStacks.of(fluid, FluidStackHooks.bucketAmount()))); } @@ -103,7 +103,12 @@ public class DefaultPlugin implements BuiltinPlugin, REIServerPlugin { @ExpectPlatform @PlatformOnly(PlatformOnly.FORGE) private static void registerForgeFluidSupport(FluidSupportProvider support) { - + throw new AssertionError(); + } + + @ExpectPlatform + private static Fluid getFluidFromBucket(BucketItem item) { + throw new AssertionError(); } @Override diff --git a/fabric/src/main/java/me/shedaniel/rei/plugin/common/fabric/DefaultPluginImpl.java b/fabric/src/main/java/me/shedaniel/rei/plugin/common/fabric/DefaultPluginImpl.java new file mode 100644 index 000000000..e86a7cb50 --- /dev/null +++ b/fabric/src/main/java/me/shedaniel/rei/plugin/common/fabric/DefaultPluginImpl.java @@ -0,0 +1,65 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.plugin.common.fabric; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.world.item.BucketItem; +import net.minecraft.world.level.material.Fluid; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.util.Optional; + +public class DefaultPluginImpl { + public static Fluid getFluidFromBucket(BucketItem item) { + Field field = getContentField(); + if (field == null) return null; + try { + return (Fluid) field.get(item); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + private static Optional field = null; + + @NotNull + private static Field getContentField() { + if (field == null) { + try { + Field field = BucketItem.class.getDeclaredField(FabricLoader.getInstance().getMappingResolver().mapFieldName("intermediary", "net.minecraft.class_1755", "field_7905", "Lnet/minecraft/class_3611;")); + field.setAccessible(true); + DefaultPluginImpl.field = Optional.of(field); + return field; + } catch (Throwable throwable) { + throwable.printStackTrace(); + DefaultPluginImpl.field = Optional.empty(); + return null; + } + } + + return field.orElse(null); + } +} diff --git a/fabric/src/main/resources/roughlyenoughitems.accessWidener b/fabric/src/main/resources/roughlyenoughitems.accessWidener index baa66082a..a9714d123 100644 --- a/fabric/src/main/resources/roughlyenoughitems.accessWidener +++ b/fabric/src/main/resources/roughlyenoughitems.accessWidener @@ -20,7 +20,6 @@ accessible field net/minecraft/world/item/alchemy/PotionBrewing accessible field net/minecraft/world/item/alchemy/PotionBrewing$Mix from Ljava/lang/Object; accessible field net/minecraft/world/item/alchemy/PotionBrewing$Mix ingredient Lnet/minecraft/world/item/crafting/Ingredient; accessible field net/minecraft/world/item/alchemy/PotionBrewing$Mix to Ljava/lang/Object; -accessible field net/minecraft/world/item/BucketItem content Lnet/minecraft/world/level/material/Fluid; accessible field net/minecraft/world/item/crafting/UpgradeRecipe addition Lnet/minecraft/world/item/crafting/Ingredient; accessible field net/minecraft/world/item/crafting/UpgradeRecipe base Lnet/minecraft/world/item/crafting/Ingredient; accessible field net/minecraft/world/item/CreativeModeTab langId Ljava/lang/String; diff --git a/forge/src/main/java/me/shedaniel/rei/plugin/common/forge/DefaultPluginImpl.java b/forge/src/main/java/me/shedaniel/rei/plugin/common/forge/DefaultPluginImpl.java index a4db8f406..e2ee44500 100644 --- a/forge/src/main/java/me/shedaniel/rei/plugin/common/forge/DefaultPluginImpl.java +++ b/forge/src/main/java/me/shedaniel/rei/plugin/common/forge/DefaultPluginImpl.java @@ -28,7 +28,9 @@ import dev.architectury.event.CompoundEventResult; import dev.architectury.hooks.fluid.forge.FluidStackHooksForge; import me.shedaniel.rei.api.common.fluid.FluidSupportProvider; import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.material.Fluid; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidUtil; @@ -55,4 +57,8 @@ public class DefaultPluginImpl { return CompoundEventResult.pass(); }); } + + public static Fluid getFluidFromBucket(BucketItem item) { + return item.getFluid(); + } } diff --git a/forge/src/main/resources/META-INF/accesstransformer.cfg b/forge/src/main/resources/META-INF/accesstransformer.cfg index d468de9f2..f43fc89ba 100644 --- a/forge/src/main/resources/META-INF/accesstransformer.cfg +++ b/forge/src/main/resources/META-INF/accesstransformer.cfg @@ -20,7 +20,6 @@ public net.minecraft.world.item.alchemy.PotionBrewing f_43494_ public net.minecraft.world.item.alchemy.PotionBrewing$Mix f_43532_ public net.minecraft.world.item.alchemy.PotionBrewing$Mix f_43533_ public net.minecraft.world.item.alchemy.PotionBrewing$Mix f_43534_ -public net.minecraft.world.item.BucketItem f_40687_ public net.minecraft.world.item.crafting.UpgradeRecipe f_44519_ public net.minecraft.world.item.crafting.UpgradeRecipe f_44518_ public net.minecraft.world.item.CreativeModeTab f_40763_ -- cgit From ad476378effa1dfd5fbef9c4d4cb5eadb9954d32 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 16 Apr 2022 03:15:46 +0800 Subject: Add shapeless indicator --- .../gui/widgets/DelegateWidgetWithBounds.java | 42 ++++ .../rei/api/client/gui/widgets/Widgets.java | 258 ++++++++------------- .../me/shedaniel/rei/impl/ClientInternals.java | 13 ++ .../crafting/DefaultCraftingCategory.java | 3 + .../displays/crafting/DefaultCraftingDisplay.java | 4 + .../displays/crafting/DefaultShapelessDisplay.java | 5 + .../gui/widget/DelegateWidgetWithTranslate.java | 86 +++++++ .../impl/client/gui/widget/InternalWidgets.java | 83 ++++--- .../rei/impl/client/gui/widget/MergedWidget.java | 66 ++++++ .../client/gui/widget/RendererWrappedWidget.java | 72 ++++++ .../client/gui/widget/VanillaWrappedWidget.java | 82 +++++++ .../assets/roughlyenoughitems/lang/de_de.json | 50 ++++ .../assets/roughlyenoughitems/lang/en_us.json | 3 +- .../assets/roughlyenoughitems/lang/pt_br.json | 57 +++-- .../assets/roughlyenoughitems/lang/zh_cn.json | 4 +- .../assets/roughlyenoughitems/lang/zh_tw.json | 4 +- 16 files changed, 609 insertions(+), 223 deletions(-) create mode 100644 api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java new file mode 100644 index 000000000..cf2a9e025 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java @@ -0,0 +1,42 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.api.client.gui.widgets; + +import me.shedaniel.math.Rectangle; + +import java.util.function.Supplier; + +public class DelegateWidgetWithBounds extends DelegateWidget { + private final Supplier bounds; + + public DelegateWidgetWithBounds(Widget widget, Supplier bounds) { + super(widget); + this.bounds = bounds; + } + + @Override + public Rectangle getBounds() { + return bounds.get(); + } +} \ No newline at end of file diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java index fee50c9d5..9dbeb363c 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java @@ -24,9 +24,7 @@ package me.shedaniel.rei.api.client.gui.widgets; import com.google.common.collect.AbstractIterator; -import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; -import com.mojang.math.Vector4f; import me.shedaniel.math.Dimension; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; @@ -37,13 +35,13 @@ import me.shedaniel.rei.impl.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.events.ContainerEventHandler; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -60,8 +58,51 @@ public final class Widgets { return ClientInternals.getWidgetsProvider().createDrawableWidget(drawable); } + public static WidgetWithBounds withTooltip(WidgetWithBounds widget, Component... texts) { + return withTooltip(widget, Arrays.asList(texts)); + } + + public static WidgetWithBounds withTooltip(WidgetWithBounds widget, Collection texts) { + return withBounds(concat( + widget, + createTooltip(widget::getBounds, texts) + ), widget::getBounds); + } + + public static Widget createTooltip(Rectangle bounds, Component... texts) { + return createTooltip(() -> bounds, Arrays.asList(texts)); + } + + public static Widget createTooltip(Rectangle bounds, Collection texts) { + return createTooltip(() -> bounds, texts); + } + + public static Widget createTooltip(Supplier bounds, Component... texts) { + return createTooltip(bounds, Arrays.asList(texts)); + } + + public static Widget createTooltip(Supplier bounds, Collection texts) { + return createTooltip(mouse -> { + if (bounds.get().contains(mouse)) { + return Tooltip.create(mouse, texts); + } else { + return null; + } + }); + } + + public static Widget createTooltip(Function tooltipSupplier) { + return createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + Point mouse = new Point(mouseX, mouseY); + Tooltip tooltip = tooltipSupplier.apply(mouse); + if (tooltip != null) { + tooltip.queue(); + } + }); + } + public static Widget wrapVanillaWidget(GuiEventListener element) { - return new VanillaWrappedWidget(element); + return ClientInternals.getWidgetsProvider().wrapVanillaWidget(element); } public static WidgetWithBounds withTranslate(Widget widget, double x, double y, double z) { @@ -69,119 +110,16 @@ public final class Widgets { } public static WidgetWithBounds withTranslate(Widget widget, Matrix4f translate) { - WidgetWithBounds widgetWithBounds = wrapWidgetWithBounds(widget); - return new WidgetWithBoundsWithTranslate(widgetWithBounds, () -> translate); + return withTranslate(widget, () -> translate); } public static WidgetWithBounds withTranslate(T widget, Function translate) { - WidgetWithBounds widgetWithBounds = wrapWidgetWithBounds(widget); - return new WidgetWithBoundsWithTranslate(widgetWithBounds, () -> translate.apply(widget)); + return withTranslate(widget, () -> translate.apply(widget)); } public static WidgetWithBounds withTranslate(Widget widget, Supplier translate) { WidgetWithBounds widgetWithBounds = wrapWidgetWithBounds(widget); - return new WidgetWithBoundsWithTranslate(widgetWithBounds, translate); - } - - private static class WidgetWithBoundsWithTranslate extends DelegateWidget { - private final Supplier translate; - - private WidgetWithBoundsWithTranslate(WidgetWithBounds widget, Supplier translate) { - super(widget); - this.translate = translate; - } - - @Override - public void render(PoseStack poseStack, int i, int j, float f) { - poseStack.pushPose(); - poseStack.last().pose().multiply(translate.get()); - Vector4f mouse = transformMouse(i, j); - super.render(poseStack, (int) mouse.x(), (int) mouse.y(), f); - poseStack.popPose(); - } - - private Vector4f transformMouse(double mouseX, double mouseY) { - Vector4f mouse = new Vector4f((float) mouseX, (float) mouseY, 0, 1); - mouse.transform(translate.get()); - return mouse; - } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - Vector4f mouse = transformMouse(mouseX, mouseY); - return super.containsMouse(mouse.x(), mouse.y()); - } - - @Override - public boolean mouseClicked(double d, double e, int i) { - Vector4f mouse = transformMouse(d, e); - return super.mouseClicked(mouse.x(), mouse.y(), i); - } - - @Override - public boolean mouseReleased(double d, double e, int i) { - Vector4f mouse = transformMouse(d, e); - return super.mouseReleased(mouse.x(), mouse.y(), i); - } - - @Override - public boolean mouseDragged(double d, double e, int i, double f, double g) { - Vector4f mouse = transformMouse(d, e); - return super.mouseDragged(mouse.x(), mouse.y(), i, f, g); - } - - @Override - public boolean mouseScrolled(double d, double e, double f) { - Vector4f mouse = transformMouse(d, e); - return super.mouseScrolled(mouse.x(), mouse.y(), f); - } - } - - private static class VanillaWrappedWidget extends Widget { - private GuiEventListener element; - - public VanillaWrappedWidget(GuiEventListener element) { - this.element = Objects.requireNonNull(element); - setFocused(element); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (element instanceof GuiComponent component) - component.setBlitOffset(getZ()); - if (element instanceof net.minecraft.client.gui.components.Widget widget) - widget.render(matrices, mouseX, mouseY, delta); - } - - @Override - public List children() { - return Collections.singletonList(element); - } - - @Nullable - @Override - public GuiEventListener getFocused() { - return element; - } - - @Override - public void setFocused(@Nullable GuiEventListener guiEventListener) { - if (guiEventListener == element) { - super.setFocused(element); - } else if (element instanceof ContainerEventHandler handler) { - handler.setFocused(guiEventListener); - } - } - - @Override - public boolean isDragging() { - return true; - } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return element.isMouseOver(mouseX, mouseY); - } + return ClientInternals.getWidgetsProvider().withTranslate(widgetWithBounds, translate); } public static WidgetWithBounds wrapRenderer(Rectangle bounds, Renderer renderer) { @@ -191,18 +129,45 @@ public final class Widgets { public static WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer) { if (renderer instanceof Widget widget) return wrapWidgetWithBoundsSupplier(widget, bounds); - return new RendererWrappedWidget(renderer, bounds); + return ClientInternals.getWidgetsProvider().wrapRenderer(bounds, renderer); } + /** + * @deprecated Use {@link #withBounds(Widget)} instead. + */ + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval public static WidgetWithBounds wrapWidgetWithBounds(Widget widget) { - return wrapWidgetWithBounds(widget, null); + return withBounds(widget); } + /** + * @deprecated Use {@link #withBounds(Widget, Rectangle)} instead. + */ + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval public static WidgetWithBounds wrapWidgetWithBounds(Widget widget, Rectangle bounds) { - return wrapWidgetWithBoundsSupplier(widget, bounds == null ? null : () -> bounds); + return withBounds(widget, bounds); } + /** + * @deprecated Use {@link #withBounds(Widget, Supplier)} instead. + */ + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval public static WidgetWithBounds wrapWidgetWithBoundsSupplier(Widget widget, Supplier bounds) { + return withBounds(widget, bounds); + } + + public static WidgetWithBounds withBounds(Widget widget) { + return wrapWidgetWithBounds(widget, null); + } + + public static WidgetWithBounds withBounds(Widget widget, Rectangle bounds) { + return wrapWidgetWithBoundsSupplier(widget, bounds == null ? null : () -> bounds); + } + + public static WidgetWithBounds withBounds(Widget widget, Supplier bounds) { if (widget instanceof WidgetWithBounds withBounds) return withBounds; if (bounds == null) @@ -210,57 +175,6 @@ public final class Widgets { return new DelegateWidgetWithBounds(widget, bounds); } - private static class RendererWrappedWidget extends WidgetWithBounds { - private final Renderer renderer; - private final Supplier bounds; - - public RendererWrappedWidget(Renderer renderer, Supplier bounds) { - this.renderer = Objects.requireNonNull(renderer); - this.bounds = Objects.requireNonNull(bounds); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - renderer.render(matrices, getBounds(), mouseX, mouseY, delta); - } - - @Override - public List children() { - if (renderer instanceof GuiEventListener listener) - return Collections.singletonList(listener); - return Collections.emptyList(); - } - - @Override - public void setZ(int z) { - renderer.setZ(z); - } - - @Override - public int getZ() { - return renderer.getZ(); - } - - @Override - public Rectangle getBounds() { - return bounds.get(); - } - } - - private static class DelegateWidgetWithBounds extends DelegateWidget { - private final Supplier bounds; - - public DelegateWidgetWithBounds(Widget widget, Supplier bounds) { - super(widget); - this.bounds = bounds; - } - - @Override - public Rectangle getBounds() { - return bounds.get(); - } - } - public static Widget createTexturedWidget(ResourceLocation identifier, Rectangle bounds) { return createTexturedWidget(identifier, bounds, 0, 0); } @@ -357,6 +271,14 @@ public final class Widgets { return createSlotBase(rectangle).color(color); } + public static Widget createShapelessIcon(Rectangle rectangle) { + return createShapelessIcon(new Point(rectangle.getMaxX() - 4, rectangle.y + 4)); + } + + public static Widget createShapelessIcon(Point topRightPos) { + return ClientInternals.getWidgetsProvider().createShapelessIcon(topRightPos); + } + public static Slot createSlot(Point point) { return ClientInternals.getWidgetsProvider().createSlot(point); } @@ -373,6 +295,14 @@ public final class Widgets { Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } + public static Widget concat(Widget... widgets) { + return concat(Arrays.asList(widgets)); + } + + public static Widget concat(List widgets) { + return ClientInternals.getWidgetsProvider().concatWidgets(widgets); + } + public static Iterable walk(Iterable listeners, Predicate predicate) { return () -> new AbstractIterator() { Stack> stack; diff --git a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java b/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java index 755ab943a..4341771d1 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java @@ -23,6 +23,7 @@ package me.shedaniel.rei.impl; +import com.mojang.math.Matrix4f; import com.mojang.serialization.DataResult; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; @@ -30,6 +31,7 @@ import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.DrawableConsumer; +import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.screen.ClickArea; @@ -37,6 +39,7 @@ import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.common.plugins.PluginManager; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -155,6 +158,12 @@ public final class ClientInternals { public interface WidgetsProvider { boolean isRenderingPanel(Panel panel); + Widget wrapVanillaWidget(GuiEventListener element); + + WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer); + + WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate); + Widget createDrawableWidget(DrawableConsumer drawable); Slot createSlot(Point point); @@ -174,5 +183,9 @@ public final class ClientInternals { DrawableConsumer createTexturedConsumer(ResourceLocation texture, int x, int y, int width, int height, float u, float v, int uWidth, int vHeight, int textureWidth, int textureHeight); DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color); + + Widget createShapelessIcon(Point point); + + Widget concatWidgets(List widgets); } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java index f4a4d0ca6..55f0ba48a 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java @@ -81,6 +81,9 @@ public class DefaultCraftingCategory implements DisplayCategory> extends BasicD return list; } + public boolean isShapeless() { + return false; + } + public static int getSlotWithSize(DefaultCraftingDisplay display, int index, int craftingGridWidth) { return getSlotWithSize(display.getInputWidth(), index, craftingGridWidth); } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultShapelessDisplay.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultShapelessDisplay.java index 502c5c61b..8f500bfb9 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultShapelessDisplay.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultShapelessDisplay.java @@ -61,4 +61,9 @@ public class DefaultShapelessDisplay extends DefaultCraftingDisplay translate; + + public DelegateWidgetWithTranslate(WidgetWithBounds widget, Supplier translate) { + super(widget); + this.translate = translate; + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + poseStack.pushPose(); + poseStack.last().pose().multiply(translate.get()); + Vector4f mouse = transformMouse(i, j); + super.render(poseStack, (int) mouse.x(), (int) mouse.y(), f); + poseStack.popPose(); + } + + private Vector4f transformMouse(double mouseX, double mouseY) { + Vector4f mouse = new Vector4f((float) mouseX, (float) mouseY, 0, 1); + mouse.transform(translate.get()); + return mouse; + } + + @Override + public boolean containsMouse(double mouseX, double mouseY) { + Vector4f mouse = transformMouse(mouseX, mouseY); + return super.containsMouse(mouse.x(), mouse.y()); + } + + @Override + public boolean mouseClicked(double d, double e, int i) { + Vector4f mouse = transformMouse(d, e); + return super.mouseClicked(mouse.x(), mouse.y(), i); + } + + @Override + public boolean mouseReleased(double d, double e, int i) { + Vector4f mouse = transformMouse(d, e); + return super.mouseReleased(mouse.x(), mouse.y(), i); + } + + @Override + public boolean mouseDragged(double d, double e, int i, double f, double g) { + Vector4f mouse = transformMouse(d, e); + return super.mouseDragged(mouse.x(), mouse.y(), i, f, g); + } + + @Override + public boolean mouseScrolled(double d, double e, double f) { + Vector4f mouse = transformMouse(d, e); + return super.mouseScrolled(mouse.x(), mouse.y(), f); + } +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java index e39b48fc5..f757bf9ad 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java @@ -23,13 +23,14 @@ package me.shedaniel.rei.impl.client.gui.widget; -import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.DrawableConsumer; +import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.common.display.Display; @@ -44,12 +45,12 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.function.Supplier; @ApiStatus.Internal @@ -141,34 +142,8 @@ public final class InternalWidgets { return new MergedWidget(widget2, widget1); } - private static class MergedWidget extends Widget { - private final List widgets; - - public MergedWidget(Widget widget1, Widget widget2) { - this.widgets = Lists.newArrayList(Objects.requireNonNull(widget1), Objects.requireNonNull(widget2)); - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - for (Widget widget : widgets) { - widget.setZ(getZ()); - widget.render(matrices, mouseX, mouseY, delta); - } - } - - @Override - public List children() { - return widgets; - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - for (Widget widget : this.widgets) { - if (widget.mouseScrolled(mouseX, mouseY, amount)) - return true; - } - return false; - } + public static Widget concatWidgets(List widgets) { + return new MergedWidget(widgets); } private static class LateRenderableWidget extends DelegateWidget implements LateRenderable { @@ -187,18 +162,34 @@ public final class InternalWidgets { return PanelWidget.isRendering(panel); } + @Override + public Widget wrapVanillaWidget(GuiEventListener element) { + if (element instanceof Widget) return (Widget) element; + return new VanillaWrappedWidget(element); + } + + @Override + public WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer) { + return new RendererWrappedWidget(renderer, bounds); + } + + @Override + public WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate) { + return new DelegateWidgetWithTranslate(widget, translate); + } + @Override public Widget createDrawableWidget(DrawableConsumer drawable) { return new DrawableWidget(drawable); } @Override - public me.shedaniel.rei.api.client.gui.widgets.Slot createSlot(Point point) { + public Slot createSlot(Point point) { return new EntryWidget(point); } @Override - public me.shedaniel.rei.api.client.gui.widgets.Slot createSlot(Rectangle bounds) { + public Slot createSlot(Rectangle bounds) { return new EntryWidget(bounds); } @@ -236,5 +227,33 @@ public final class InternalWidgets { public DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color) { return new FillRectangleDrawableConsumer(rectangle, color); } + + @Override + public Widget createShapelessIcon(Point point) { + int magnification; + double scale = Minecraft.getInstance().getWindow().getGuiScale(); + if (scale >= 1 && scale <= 4 && scale == Math.floor(scale)) { + magnification = (int) scale; + } else if (scale > 4 && scale == Math.floor(scale)) { + magnification = 1; + for (int i = 4; i >= 1; i--) { + if (scale % i == 0) { + magnification = i; + break; + } + } + } else { + magnification = 4; + } + Rectangle bounds = new Rectangle(point.getX() - 9, point.getY() + 1, 8, 8); + Widget widget = Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems:textures/gui/shapeless_icon_" + magnification + "x.png"), bounds.getX(), bounds.getY(), 0, 0, bounds.getWidth(), bounds.getHeight(), 1, 1, 1, 1); + return Widgets.withTooltip(Widgets.withBounds(widget, bounds), + new TranslatableComponent("text.rei.shapeless")); + } + + @Override + public Widget concatWidgets(List widgets) { + return InternalWidgets.concatWidgets(widgets); + } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java new file mode 100644 index 000000000..e419a7db7 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java @@ -0,0 +1,66 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.gui.widget; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import net.minecraft.client.gui.components.events.GuiEventListener; + +import java.util.List; +import java.util.Objects; + +public class MergedWidget extends Widget { + private final List widgets; + + public MergedWidget(Widget widget1, Widget widget2) { + this.widgets = Lists.newArrayList(Objects.requireNonNull(widget1), Objects.requireNonNull(widget2)); + } + + public MergedWidget(List widgets) { + this.widgets = widgets; + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + for (Widget widget : widgets) { + widget.setZ(getZ()); + widget.render(matrices, mouseX, mouseY, delta); + } + } + + @Override + public List children() { + return widgets; + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + for (Widget widget : this.widgets) { + if (widget.mouseScrolled(mouseX, mouseY, amount)) + return true; + } + return false; + } +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java new file mode 100644 index 000000000..97d9f3e3d --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java @@ -0,0 +1,72 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.gui.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import net.minecraft.client.gui.components.events.GuiEventListener; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +public class RendererWrappedWidget extends WidgetWithBounds { + private final Renderer renderer; + private final Supplier bounds; + + public RendererWrappedWidget(Renderer renderer, Supplier bounds) { + this.renderer = Objects.requireNonNull(renderer); + this.bounds = Objects.requireNonNull(bounds); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + renderer.render(matrices, getBounds(), mouseX, mouseY, delta); + } + + @Override + public List children() { + if (renderer instanceof GuiEventListener listener) + return Collections.singletonList(listener); + return Collections.emptyList(); + } + + @Override + public void setZ(int z) { + renderer.setZ(z); + } + + @Override + public int getZ() { + return renderer.getZ(); + } + + @Override + public Rectangle getBounds() { + return bounds.get(); + } +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java new file mode 100644 index 000000000..2aacd5e73 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java @@ -0,0 +1,82 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.gui.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.components.events.ContainerEventHandler; +import net.minecraft.client.gui.components.events.GuiEventListener; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class VanillaWrappedWidget extends Widget { + private GuiEventListener element; + + public VanillaWrappedWidget(GuiEventListener element) { + this.element = Objects.requireNonNull(element); + setFocused(element); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (element instanceof GuiComponent component) + component.setBlitOffset(getZ()); + if (element instanceof net.minecraft.client.gui.components.Widget widget) + widget.render(matrices, mouseX, mouseY, delta); + } + + @Override + public List children() { + return Collections.singletonList(element); + } + + @Nullable + @Override + public GuiEventListener getFocused() { + return element; + } + + @Overri