From 23918a88147f9fe61def22f6f6bf46c42203b137 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 4 May 2026 12:25:48 +1000 Subject: [PATCH 1/9] start working on generic recipe viewer slot --- .../integration/emi/EmiRecipeViewerSlot.java | 120 ++++++++++++++++++ .../emi/recipe/EMISlotWidgetWrapper.java | 1 - .../integration/jei/JeiRecipeViewerSlot.java | 82 ++++++++++++ .../integration/jei/ModularUIJeiPlugin.java | 10 ++ .../recipeviewer/RecipeViewerSlotWidget.java | 38 ++++++ .../integration/rei/ReiRecipeViewerSlot.java | 69 ++++++++++ 6 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java create mode 100644 src/main/java/brachy/modularui/integration/jei/JeiRecipeViewerSlot.java create mode 100644 src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java create mode 100644 src/main/java/brachy/modularui/integration/rei/ReiRecipeViewerSlot.java diff --git a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java new file mode 100644 index 0000000..d4bc104 --- /dev/null +++ b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java @@ -0,0 +1,120 @@ +package brachy.modularui.integration.emi; + +import brachy.modularui.integration.recipeviewer.RecipeSlotRole; +import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; +import brachy.modularui.integration.recipeviewer.entry.EntryList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidEntryList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidStackList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidTagList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemEntryList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemStackList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemTagList; + +import dev.emi.emi.api.forge.ForgeEmiStack; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.SlotWidget; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Collections; +import java.util.List; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class EmiRecipeViewerSlot extends RecipeViewerSlotWidget { + + private SlotWidget slot; + private int x, y; + + private RecipeSlotRole recipeSlotRole; + private EntryList value; + + public EmiRecipeViewerSlot() { + super(); + recipeSlotRole = RecipeSlotRole.RENDER_ONLY; + } + + @Override + public EmiRecipeViewerSlot recipeSlotRole(RecipeSlotRole recipeSlotRole) { + this.recipeSlotRole = recipeSlotRole; + return getThis(); + } + + @Override + public EmiRecipeViewerSlot value(FluidEntryList fluidEntryList) { + value = fluidEntryList; + return getThis(); + } + + @Override + public EmiRecipeViewerSlot value(ItemEntryList itemEntryList) { + value = itemEntryList; + return getThis(); + } + + @Override + public EmiRecipeViewerSlot value(ItemStack stack) { + value = ItemStackList.of(stack); + return getThis(); + } + + @Override + public EmiRecipeViewerSlot value(FluidStack stack) { + value = FluidStackList.of(stack); + return getThis(); + } + + @Override + public EmiRecipeViewerSlot chance(float chance) { + return getThis(); + } + + private void rebuildEmiSlot() {} + + + public static class EmiIngredientHandler { + + public static List toEmiIngredient(ItemEntryList list, float xeiChance, + UnaryOperator realStack) { + if (list instanceof ItemTagList tagList) { + return tagList.getEntries().stream() + .map(ItemTagList.ItemTagEntry::stacks) + .map(stream -> toEmiIngredient(stream, realStack).setChance(xeiChance)) + .collect(Collectors.toList()); + } + if (list instanceof ItemStackList stackList) { + return List.of(toEmiIngredient(stackList.stream(), realStack).setChance(xeiChance)); + + } + return Collections.emptyList(); + } + + public static List toEmiIngredient(FluidEntryList list, float xeiChance) { + if (list instanceof FluidTagList tagList) { + return tagList.getEntries().stream() + .map(FluidTagList.FluidTagEntry::stacks) + .map(stream -> toEMIIngredient(stream).setChance(xeiChance)) + .collect(Collectors.toList()); + } + + if (list instanceof FluidStackList stackList) { + return List.of(toEMIIngredient(stackList.stream()).setChance(xeiChance)); + } + + return Collections.emptyList(); + } + + private static EmiIngredient toEmiIngredient(Stream stream, UnaryOperator realStack) { + return EmiIngredient.of(stream.map(realStack).map(EmiStack::of).toList()); + } + + + private static EmiIngredient toEMIIngredient(Stream stream) { + return EmiIngredient.of(stream.map(ForgeEmiStack::of).toList()); + } + + } +} diff --git a/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java b/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java index 2551bc0..fbf9c03 100644 --- a/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java +++ b/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java @@ -33,7 +33,6 @@ public EMISlotWidgetWrapper(SlotWidget slotWidget) { @Override public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { - super.draw(context, widgetTheme); context.getGraphics().pose().translate(-this.x, -this.y, 0); this.slotWidget.render(context.getGraphics(), context.getMouseX(), context.getMouseY(), context.getRenderPartialTicks()); context.getGraphics().pose().translate(this.x, this.y, 0); diff --git a/src/main/java/brachy/modularui/integration/jei/JeiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/jei/JeiRecipeViewerSlot.java new file mode 100644 index 0000000..66598ab --- /dev/null +++ b/src/main/java/brachy/modularui/integration/jei/JeiRecipeViewerSlot.java @@ -0,0 +1,82 @@ +package brachy.modularui.integration.jei; + +import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidEntryList; + +import brachy.modularui.integration.recipeviewer.entry.item.ItemEntryList; + +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.runtime.IIngredientManager; +import mezz.jei.common.input.ClickableIngredient; + +import mezz.jei.common.util.ImmutableRect2i; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; + +import static brachy.modularui.integration.jei.ModularUIJeiPlugin.jeiHelpers; + +public class JeiRecipeViewerSlot { + + public static class JeiIngredientHandler { + + public static List toJeiIngredient(FluidEntryList list) { + return list.getStacks() + .stream() + .filter(stack -> !stack.isEmpty()) + .map(JeiIngredientHandler::getJEIFluid) + .toList(); + } + + public static List toJeiIngredientClickable(FluidEntryList list, int x, int y, int w, int h) { + return list.getStacks() + .stream() + .filter(stack -> !stack.isEmpty()) + .map(stack -> getJEIFluidClickable(stack, x, y, w, h)) + .toList(); + } + + public static Object getJEIFluid(FluidStack fluidStack) { + return jeiHelpers.getPlatformFluidHelper().create(fluidStack.getFluid(), fluidStack.getAmount(), fluidStack.getTag()); + } + + public static @Nullable Object getJEIFluidClickable(FluidStack fluidStack, int x, int y, int w, int h) { + var ingredient = jeiHelpers.getPlatformFluidHelper().create(fluidStack.getFluid(), fluidStack.getAmount(), fluidStack.getTag()); + return jeiHelpers.getIngredientManager().createTypedIngredient(ingredient) + .map(typedIngredient -> new ClickableIngredient<>(typedIngredient, new ImmutableRect2i(x, y, w, h))) + .orElse(null); + } + + public static @Nullable Object getJEIStackClickable(ItemStack stack, int x, int y, int w, int h) { + IIngredientManager ingredientManager = jeiHelpers.getIngredientManager(); + return ingredientManager.createTypedIngredient(VanillaTypes.ITEM_STACK, stack) + .map(typedIngredient -> new ClickableIngredient<>(typedIngredient, new ImmutableRect2i(x, y, w, h))) + .orElse(null); + } + + public static List toJeiIngredient(ItemEntryList list, UnaryOperator realStack) { + return list.getStacks() + .stream() + .filter(stack -> !stack.isEmpty()) + .map(realStack) + .collect(Collectors.toList()); + } + + public static List toJeiIngredientClickable(ItemEntryList list, int x, int y, int w, int h, + UnaryOperator realStack) { + return list.getStacks() + .stream() + .filter(stack -> !stack.isEmpty()) + .map(realStack) + .map(stack -> getJEIStackClickable(stack, x, y, w, h)) + .collect(Collectors.toList()); + } + + } +} diff --git a/src/main/java/brachy/modularui/integration/jei/ModularUIJeiPlugin.java b/src/main/java/brachy/modularui/integration/jei/ModularUIJeiPlugin.java index 7a1f4dd..868aca7 100644 --- a/src/main/java/brachy/modularui/integration/jei/ModularUIJeiPlugin.java +++ b/src/main/java/brachy/modularui/integration/jei/ModularUIJeiPlugin.java @@ -7,6 +7,10 @@ import brachy.modularui.screen.ModularContainerMenu; import brachy.modularui.screen.ScreenWrapper; +import mezz.jei.api.helpers.IJeiHelpers; + +import mezz.jei.api.registration.IRecipeCategoryRegistration; + import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.resources.ResourceLocation; @@ -26,6 +30,7 @@ public class ModularUIJeiPlugin implements IModPlugin { @Getter private static IJeiRuntime runtime = null; + public static IJeiHelpers jeiHelpers; public static boolean hasRuntime() { return runtime != null; @@ -41,6 +46,11 @@ public void onRuntimeAvailable(IJeiRuntime jeiRuntime) { runtime = jeiRuntime; } + @Override + public void registerCategories(IRecipeCategoryRegistration registration) { + jeiHelpers = registration.getJeiHelpers(); + } + @Override public void registerGuiHandlers(IGuiHandlerRegistration registration) { if (ModularUI.Mods.REI.isLoaded() || ModularUI.Mods.EMI.isLoaded()) return; diff --git a/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java b/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java new file mode 100644 index 0000000..0065ad9 --- /dev/null +++ b/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java @@ -0,0 +1,38 @@ +package brachy.modularui.integration.recipeviewer; + +import brachy.modularui.ModularUI; +import brachy.modularui.api.widget.Interactable; +import brachy.modularui.integration.emi.EmiRecipeViewerSlot; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidEntryList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemEntryList; +import brachy.modularui.widget.Widget; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import org.apache.commons.lang3.NotImplementedException; + +public abstract class RecipeViewerSlotWidget> extends Widget implements Interactable { + + public abstract T recipeSlotRole(RecipeSlotRole recipeSlotRole); + + public abstract T value(FluidEntryList fluidEntryList); + public abstract T value(ItemEntryList itemEntryList); + public abstract T value(ItemStack stack); + public abstract T value(FluidStack stack); + + public abstract T chance(float chance); + + public static RecipeViewerSlotWidget create() { + if (!ModularUI.Mods.isRecipeViewerLoaded()) throw new IllegalStateException("Cannot create recipe viewer slot without a recipe viewer mod loaded."); + + if (ModularUI.Mods.EMI.isLoaded()) { + return new EmiRecipeViewerSlot(); + } //else if (ModularUI.Mods.JEI.isLoaded()) { + // return new JeiRecipeViewerSlot(); + //}/else { + // return new ReiRecipeViewerSlot(); + //} + throw new NotImplementedException(); + } +} diff --git a/src/main/java/brachy/modularui/integration/rei/ReiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/rei/ReiRecipeViewerSlot.java new file mode 100644 index 0000000..462c499 --- /dev/null +++ b/src/main/java/brachy/modularui/integration/rei/ReiRecipeViewerSlot.java @@ -0,0 +1,69 @@ +package brachy.modularui.integration.rei; + +import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidEntryList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidStackList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidTagList; + +import brachy.modularui.integration.recipeviewer.entry.item.ItemEntryList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemStackList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemTagList; + +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.util.EntryStacks; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Collections; +import java.util.List; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ReiRecipeViewerSlot { + + public static class ReiIngredientHandler { + + private static EntryIngredient toReiIngredient(Stream stream) { + return EntryIngredient.of(stream + .map(s -> dev.architectury.fluid.FluidStack.create(s.getFluid(), s.getAmount(), s.getTag())) + .map(EntryStacks::of) + .toList()); + } + + private static EntryIngredient toReiIngredient(Stream stream, UnaryOperator realStack) { + return EntryIngredient.of(stream.map(realStack) + .map(EntryStacks::of) + .toList()); + } + + public static List toReiIngredient(FluidEntryList list) { + if (list instanceof FluidTagList tagList) { + return tagList.getEntries().stream() + .map(FluidTagList.FluidTagEntry::stacks) + .map(ReiIngredientHandler::toReiIngredient) + .collect(Collectors.toList()); + } + + if (list instanceof FluidStackList stackList) { + return List.of(toReiIngredient(stackList.stream())); + } + return Collections.emptyList(); + } + + public static List toReiIngredient(ItemEntryList list, UnaryOperator realStack) { + if (list instanceof ItemTagList tagList) { + return tagList.getEntries().stream() + .map(ItemTagList.ItemTagEntry::stacks) + .map(stream -> toReiIngredient(stream, realStack)) + .collect(Collectors.toList()); + + } + if (list instanceof ItemStackList stackList) { + return List.of(toReiIngredient(stackList.stream(), realStack)); + } + return Collections.emptyList(); + } + } +} From e0b9ab8f8e49b3ce1275b82536d097efcf17e6db Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 4 May 2026 14:49:46 +1000 Subject: [PATCH 2/9] get rendering working --- .../integration/emi/EmiRecipeViewerSlot.java | 107 +++++++++++++----- .../emi/recipe/ModularUIEmiRecipe.java | 41 +------ .../brachy/modularui/test/TestMachine.java | 31 ++++- 3 files changed, 114 insertions(+), 65 deletions(-) diff --git a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java index d4bc104..b9634f8 100644 --- a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java +++ b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java @@ -1,5 +1,6 @@ package brachy.modularui.integration.emi; +import brachy.modularui.drawable.ClientTooltipComponentIcon; import brachy.modularui.integration.recipeviewer.RecipeSlotRole; import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; import brachy.modularui.integration.recipeviewer.entry.EntryList; @@ -10,111 +11,161 @@ import brachy.modularui.integration.recipeviewer.entry.item.ItemStackList; import brachy.modularui.integration.recipeviewer.entry.item.ItemTagList; +import brachy.modularui.screen.viewport.ModularGuiContext; +import brachy.modularui.theme.WidgetThemeEntry; + import dev.emi.emi.api.forge.ForgeEmiStack; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.api.widget.SlotWidget; +import dev.emi.emi.api.widget.TankWidget; + +import lombok.Getter; +import lombok.experimental.Accessors; + +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.fluids.FluidStack; -import java.util.Collections; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; import java.util.List; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class EmiRecipeViewerSlot extends RecipeViewerSlotWidget { - private SlotWidget slot; + @ApiStatus.Internal + @Getter + private SlotWidget slotWidget; private int x, y; + @Accessors(fluent = true) + @Getter private RecipeSlotRole recipeSlotRole; private EntryList value; + private float chance = 1f; public EmiRecipeViewerSlot() { super(); + slotWidget = new SlotWidget(EmiIngredient.of(Ingredient.EMPTY), 0, 0); recipeSlotRole = RecipeSlotRole.RENDER_ONLY; + + tooltipAutoUpdate(true); + tooltipDynamic(tooltip -> { + for (ClientTooltipComponent ctc : this.slotWidget.getTooltip(getContext().getAbsMouseX(), getContext().getAbsMouseY())) { + tooltip.addDrawableLine(new ClientTooltipComponentIcon(ctc)); + } + }); } @Override public EmiRecipeViewerSlot recipeSlotRole(RecipeSlotRole recipeSlotRole) { this.recipeSlotRole = recipeSlotRole; + slotWidget.catalyst(recipeSlotRole == RecipeSlotRole.CATALYST); return getThis(); } @Override public EmiRecipeViewerSlot value(FluidEntryList fluidEntryList) { value = fluidEntryList; + rebuildEmiSlot(); return getThis(); } @Override public EmiRecipeViewerSlot value(ItemEntryList itemEntryList) { value = itemEntryList; + rebuildEmiSlot(); return getThis(); } @Override public EmiRecipeViewerSlot value(ItemStack stack) { value = ItemStackList.of(stack); + rebuildEmiSlot(); return getThis(); } @Override public EmiRecipeViewerSlot value(FluidStack stack) { value = FluidStackList.of(stack); + rebuildEmiSlot(); return getThis(); } @Override public EmiRecipeViewerSlot chance(float chance) { + this.chance = chance; return getThis(); } - private void rebuildEmiSlot() {} + private void rebuildEmiSlot() { + if (value instanceof ItemEntryList itemEntryList) { + slotWidget = new SlotWidget(EmiIngredientHandler.toEmiIngredient(itemEntryList, chance, UnaryOperator.identity()), 0, 0); + } else { + slotWidget = new TankWidget(EmiIngredientHandler.toEmiIngredient((FluidEntryList)value, chance), 0, 0, 18, 18, 1); + } + } + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + context.getGraphics().pose().translate(-this.x, -this.y, 0); + this.slotWidget.render(context.getGraphics(), context.getMouseX(), context.getMouseY(), context.getRenderPartialTicks()); + context.getGraphics().pose().translate(this.x, this.y, 0); + } + + @Override + public Result onMousePressed(int button) { + this.slotWidget.mouseClicked(getContext().getMouseX(), getContext().getAbsMouseY(), button); + return Result.SUCCESS; + } + @Override + public Result onKeyPressed(int keyCode, int scanCode, int modifiers) { + return this.slotWidget.keyPressed(keyCode, scanCode, modifiers) ? Result.SUCCESS : Result.ACCEPT; + } public static class EmiIngredientHandler { - public static List toEmiIngredient(ItemEntryList list, float xeiChance, + public static EmiIngredient toEmiIngredient(ItemEntryList list, float xeiChance, UnaryOperator realStack) { + List ingredients = new ArrayList<>(); if (list instanceof ItemTagList tagList) { - return tagList.getEntries().stream() + ingredients.addAll(tagList.getEntries().stream() .map(ItemTagList.ItemTagEntry::stacks) - .map(stream -> toEmiIngredient(stream, realStack).setChance(xeiChance)) - .collect(Collectors.toList()); + .map(stream -> EmiIngredient.of(stream.map(realStack).map(EmiStack::of).toList()).setChance(xeiChance)).toList()); } if (list instanceof ItemStackList stackList) { - return List.of(toEmiIngredient(stackList.stream(), realStack).setChance(xeiChance)); - + ingredients.add(EmiIngredient.of(stackList.stream().map(realStack).map(EmiStack::of).toList()).setChance(xeiChance)); } - return Collections.emptyList(); + + if (ingredients.isEmpty()) return EmiIngredient.of(Ingredient.EMPTY); + if (ingredients.size() == 1) return ingredients.get(0); + return EmiIngredient.of(ingredients); } - public static List toEmiIngredient(FluidEntryList list, float xeiChance) { + public static EmiIngredient toEmiIngredient(FluidEntryList list, float xeiChance) { + + List ingredients = new ArrayList<>(); + if (list instanceof FluidTagList tagList) { - return tagList.getEntries().stream() + ingredients.addAll(tagList.getEntries().stream() .map(FluidTagList.FluidTagEntry::stacks) - .map(stream -> toEMIIngredient(stream).setChance(xeiChance)) - .collect(Collectors.toList()); + .map(stream -> EmiIngredient.of(stream.map(ForgeEmiStack::of).toList()).setChance(xeiChance)) + .toList() + ); } if (list instanceof FluidStackList stackList) { - return List.of(toEMIIngredient(stackList.stream()).setChance(xeiChance)); + ingredients.add(EmiIngredient.of(stackList.stream().map(ForgeEmiStack::of).toList()).setChance(xeiChance)); } - return Collections.emptyList(); + if (ingredients.isEmpty()) return EmiIngredient.of(Ingredient.EMPTY); + if (ingredients.size() == 1) return ingredients.get(0); + return EmiIngredient.of(ingredients); } - - private static EmiIngredient toEmiIngredient(Stream stream, UnaryOperator realStack) { - return EmiIngredient.of(stream.map(realStack).map(EmiStack::of).toList()); - } - - - private static EmiIngredient toEMIIngredient(Stream stream) { - return EmiIngredient.of(stream.map(ForgeEmiStack::of).toList()); - } - } } diff --git a/src/main/java/brachy/modularui/integration/emi/recipe/ModularUIEmiRecipe.java b/src/main/java/brachy/modularui/integration/emi/recipe/ModularUIEmiRecipe.java index 544ae51..4166c94 100644 --- a/src/main/java/brachy/modularui/integration/emi/recipe/ModularUIEmiRecipe.java +++ b/src/main/java/brachy/modularui/integration/emi/recipe/ModularUIEmiRecipe.java @@ -1,19 +1,16 @@ package brachy.modularui.integration.emi.recipe; import brachy.modularui.ModularUI; -import brachy.modularui.api.IThemeApi; import brachy.modularui.api.drawable.IRichTextBuilder; import brachy.modularui.api.widget.ITooltip; import brachy.modularui.api.widget.IWidget; import brachy.modularui.drawable.text.RichText; +import brachy.modularui.integration.emi.EmiRecipeViewerSlot; import brachy.modularui.integration.recipeviewer.RecipeSlotRole; -import brachy.modularui.integration.recipeviewer.handlers.IngredientProvider; import brachy.modularui.screen.EmbedHandler; import brachy.modularui.screen.ModularPanel; import brachy.modularui.screen.ModularScreen; import brachy.modularui.screen.RichTooltip; -import brachy.modularui.theme.WidgetThemeKey; -import brachy.modularui.widgets.slot.FluidSlot; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -27,7 +24,6 @@ import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.api.widget.Bounds; import dev.emi.emi.api.widget.SlotWidget; -import dev.emi.emi.api.widget.TankWidget; import dev.emi.emi.api.widget.Widget; import dev.emi.emi.api.widget.WidgetHolder; import org.jetbrains.annotations.Nullable; @@ -118,41 +114,14 @@ public ModularPanel transform(ModularPanel panel) { } public IWidget transformWidget(IWidget widget, Iterator in, Iterator out) { - if (!(widget instanceof IngredientProvider provider)) return widget; - RecipeSlotRole role = provider.getRecipeRole(); - if (role == RecipeSlotRole.RENDER_ONLY) return widget; + if (!(widget instanceof EmiRecipeViewerSlot recipeViewerSlot)) return widget; - EmiIngredient ingr = EmiStack.EMPTY; - if (role == RecipeSlotRole.INPUT && in.hasNext()) { - ingr = in.next(); - } else if (role == RecipeSlotRole.OUTPUT && out.hasNext()) { - ingr = out.next(); + if (recipeViewerSlot.recipeSlotRole() == RecipeSlotRole.OUTPUT) { + recipeViewerSlot.getSlotWidget().recipeContext(this); } - SlotWidget emiSlot = null; - WidgetThemeKey widgetThemeKey = null; - if (widget instanceof FluidSlot slot) { - if (!slot.isAlwaysShowFull()) { - emiSlot = new TankWidget(ingr, 0, 0, slot.getArea().width, slot.getArea().height, slot.getCapacity()); - } - widgetThemeKey = IThemeApi.FLUID_SLOT; - } - if (emiSlot == null) emiSlot = new SlotWidget(ingr, 0, 0); - if (widgetThemeKey == null) widgetThemeKey = IThemeApi.ITEM_SLOT; - - emiSlot.drawBack(false); - - if (role == RecipeSlotRole.CATALYST) { - emiSlot.catalyst(true); - } else if (role == RecipeSlotRole.OUTPUT) { - emiSlot.recipeContext(this); - } - - return new EMISlotWidgetWrapper<>(emiSlot) - .copyResizerOf(widget) - .copyVisualsOf(widget) - .widgetTheme(widgetThemeKey); + return recipeViewerSlot; } @Override diff --git a/src/main/java/brachy/modularui/test/TestMachine.java b/src/main/java/brachy/modularui/test/TestMachine.java index 8bfa1a9..b07d2c3 100644 --- a/src/main/java/brachy/modularui/test/TestMachine.java +++ b/src/main/java/brachy/modularui/test/TestMachine.java @@ -10,6 +10,8 @@ import brachy.modularui.factory.PosGuiData; import brachy.modularui.integration.emi.recipe.ModularUIEmiRecipe; import brachy.modularui.integration.recipeviewer.RecipeSlotRole; +import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidStackList; import brachy.modularui.screen.ModularPanel; import brachy.modularui.screen.ModularScreen; import brachy.modularui.screen.UISettings; @@ -42,9 +44,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemHandlerHelper; @@ -285,6 +289,31 @@ public static IWidget buildMachineUI(IItemHandler in, IItemHandler out, IDoubleV .slot(new ModularSlot(out, i).canPut(false)) .recipeRole(RecipeSlotRole.OUTPUT))); } + + public static IWidget buildViewerUI(Recipe recipe) { + return Flow.row().name("slots") + .coverChildren() + .center() + .childPadding(8) + .child(SlotGroupWidget.rect(2, 2, i -> { + var in = i >= recipe.in.size() ? ItemStack.EMPTY : recipe.in.get(i); + if (in == null) in = ItemStack.EMPTY; + return RecipeViewerSlotWidget.create() + .recipeSlotRole(RecipeSlotRole.INPUT) + .value(FluidStackList.of(List.of(new FluidStack(Fluids.LAVA, 1000), new FluidStack(Fluids.WATER, 100)))); + })) + .child(new ProgressWidget() + .value(DoubleValue.simulateProgress(5000)) + .size(20) + .texture(GuiTextures.PROGRESS_ARROW, 20)) + .child(SlotGroupWidget.rect(2, 2, i -> { + var out = i >= recipe.out.size() ? ItemStack.EMPTY : recipe.out.get(i); + if (out == null) out = ItemStack.EMPTY; + return RecipeViewerSlotWidget.create() + .recipeSlotRole(RecipeSlotRole.OUTPUT) + .value(out); + })); + } } public static class EMI { @@ -294,7 +323,7 @@ public static class EMI { public static void register(EmiRegistry registry) { registry.addCategory(CATEGORY); Recipes.list.stream() - .map(r -> new RecipeDisplay(() -> Recipes.buildMachineUI(EMPTY_INFINITE_ITEM_HANDLER, EMPTY_INFINITE_ITEM_HANDLER, DoubleValue.simulateProgress(5000)), r)) + .map(r -> new RecipeDisplay(() -> Recipes.buildViewerUI(r), r)) .forEach(registry::addRecipe); } From bd3a527130ed5c0977b2945f898d96ab3ccdfdc1 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 4 May 2026 16:11:48 +1000 Subject: [PATCH 3/9] update background rendering --- .../integration/emi/EmiRecipeViewerSlot.java | 18 ++----- .../emi/recipe/EMISlotWidgetWrapper.java | 51 ------------------- .../recipeviewer/RecipeViewerSlotWidget.java | 12 ++++- 3 files changed, 14 insertions(+), 67 deletions(-) delete mode 100644 src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java diff --git a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java index b9634f8..5205cbb 100644 --- a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java +++ b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java @@ -1,6 +1,7 @@ package brachy.modularui.integration.emi; import brachy.modularui.drawable.ClientTooltipComponentIcon; +import brachy.modularui.drawable.GuiTextures; import brachy.modularui.integration.recipeviewer.RecipeSlotRole; import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; import brachy.modularui.integration.recipeviewer.entry.EntryList; @@ -72,6 +73,7 @@ public EmiRecipeViewerSlot recipeSlotRole(RecipeSlotRole recipeSlotRole) { public EmiRecipeViewerSlot value(FluidEntryList fluidEntryList) { value = fluidEntryList; rebuildEmiSlot(); + background(GuiTextures.SLOT_FLUID); return getThis(); } @@ -79,20 +81,7 @@ public EmiRecipeViewerSlot value(FluidEntryList fluidEntryList) { public EmiRecipeViewerSlot value(ItemEntryList itemEntryList) { value = itemEntryList; rebuildEmiSlot(); - return getThis(); - } - - @Override - public EmiRecipeViewerSlot value(ItemStack stack) { - value = ItemStackList.of(stack); - rebuildEmiSlot(); - return getThis(); - } - - @Override - public EmiRecipeViewerSlot value(FluidStack stack) { - value = FluidStackList.of(stack); - rebuildEmiSlot(); + background(GuiTextures.SLOT_ITEM); return getThis(); } @@ -108,6 +97,7 @@ private void rebuildEmiSlot() { } else { slotWidget = new TankWidget(EmiIngredientHandler.toEmiIngredient((FluidEntryList)value, chance), 0, 0, 18, 18, 1); } + slotWidget.drawBack(false); } @Override diff --git a/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java b/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java deleted file mode 100644 index fbf9c03..0000000 --- a/src/main/java/brachy/modularui/integration/emi/recipe/EMISlotWidgetWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -package brachy.modularui.integration.emi.recipe; - -import brachy.modularui.api.widget.Interactable; -import brachy.modularui.drawable.ClientTooltipComponentIcon; -import brachy.modularui.screen.viewport.ModularGuiContext; -import brachy.modularui.theme.WidgetThemeEntry; -import brachy.modularui.widget.Widget; - -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; - -import dev.emi.emi.api.widget.Bounds; -import dev.emi.emi.api.widget.SlotWidget; - -public class EMISlotWidgetWrapper> extends Widget implements Interactable { - - private final SlotWidget slotWidget; - private final int x, y; - - public EMISlotWidgetWrapper(SlotWidget slotWidget) { - this.slotWidget = slotWidget; - Bounds bounds = this.slotWidget.getBounds(); - size(bounds.width(), bounds.height()); - this.x = bounds.x(); - this.y = bounds.y(); - - tooltipAutoUpdate(true); - tooltipDynamic(tooltip -> { - for (ClientTooltipComponent ctc : this.slotWidget.getTooltip(getContext().getAbsMouseX(), getContext().getAbsMouseY())) { - tooltip.addDrawableLine(new ClientTooltipComponentIcon(ctc)); - } - }); - } - - @Override - public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { - context.getGraphics().pose().translate(-this.x, -this.y, 0); - this.slotWidget.render(context.getGraphics(), context.getMouseX(), context.getMouseY(), context.getRenderPartialTicks()); - context.getGraphics().pose().translate(this.x, this.y, 0); - } - - @Override - public Result onMousePressed(int button) { - this.slotWidget.mouseClicked(getContext().getMouseX(), getContext().getAbsMouseY(), button); - return Result.SUCCESS; - } - - @Override - public Result onKeyPressed(int keyCode, int scanCode, int modifiers) { - return this.slotWidget.keyPressed(keyCode, scanCode, modifiers) ? Result.SUCCESS : Result.ACCEPT; - } -} diff --git a/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java b/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java index 0065ad9..bf4a181 100644 --- a/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java +++ b/src/main/java/brachy/modularui/integration/recipeviewer/RecipeViewerSlotWidget.java @@ -4,7 +4,9 @@ import brachy.modularui.api.widget.Interactable; import brachy.modularui.integration.emi.EmiRecipeViewerSlot; import brachy.modularui.integration.recipeviewer.entry.fluid.FluidEntryList; +import brachy.modularui.integration.recipeviewer.entry.fluid.FluidStackList; import brachy.modularui.integration.recipeviewer.entry.item.ItemEntryList; +import brachy.modularui.integration.recipeviewer.entry.item.ItemStackList; import brachy.modularui.widget.Widget; import net.minecraft.world.item.ItemStack; @@ -18,8 +20,14 @@ public abstract class RecipeViewerSlotWidget public abstract T value(FluidEntryList fluidEntryList); public abstract T value(ItemEntryList itemEntryList); - public abstract T value(ItemStack stack); - public abstract T value(FluidStack stack); + + public T value(ItemStack stack) { + return value(ItemStackList.of(stack)); + } + + public T value(FluidStack stack) { + return value(FluidStackList.of(stack)); + } public abstract T chance(float chance); From 06b1bb0883bbb2b7d2808730a7c0e8f59f2d61c6 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 4 May 2026 22:53:05 +1000 Subject: [PATCH 4/9] fix size --- .../brachy/modularui/integration/emi/EmiRecipeViewerSlot.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java index 5205cbb..f4c0995 100644 --- a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java +++ b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java @@ -54,6 +54,8 @@ public EmiRecipeViewerSlot() { slotWidget = new SlotWidget(EmiIngredient.of(Ingredient.EMPTY), 0, 0); recipeSlotRole = RecipeSlotRole.RENDER_ONLY; + size(18, 18); + tooltipAutoUpdate(true); tooltipDynamic(tooltip -> { for (ClientTooltipComponent ctc : this.slotWidget.getTooltip(getContext().getAbsMouseX(), getContext().getAbsMouseY())) { From 5a23f751283c11365bc19825a329690bc436608a Mon Sep 17 00:00:00 2001 From: Gustavo Date: Tue, 5 May 2026 09:31:22 +1000 Subject: [PATCH 5/9] make text widget use a supplier --- .../drawable/text/DynamicComponent.java | 7 +++++ .../integration/emi/EmiRecipeViewerSlot.java | 1 - .../widgets/ScrollingTextWidget.java | 4 +-- .../brachy/modularui/widgets/TextWidget.java | 27 ++++++++++++------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/brachy/modularui/drawable/text/DynamicComponent.java b/src/main/java/brachy/modularui/drawable/text/DynamicComponent.java index 8d6915f..e1aa7d1 100644 --- a/src/main/java/brachy/modularui/drawable/text/DynamicComponent.java +++ b/src/main/java/brachy/modularui/drawable/text/DynamicComponent.java @@ -5,6 +5,8 @@ import brachy.modularui.screen.viewport.GuiContext; import brachy.modularui.theme.WidgetTheme; +import brachy.modularui.widgets.TextWidget; + import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentContents; @@ -62,6 +64,11 @@ private Component getComp() { return getComp().getVisualOrderText(); } + @Override + public TextWidget asWidget() { + return new TextWidget<>(this::getComp); + } + @Override public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { Component comp = getComp(); diff --git a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java index f4c0995..44076a1 100644 --- a/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java +++ b/src/main/java/brachy/modularui/integration/emi/EmiRecipeViewerSlot.java @@ -28,7 +28,6 @@ import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/brachy/modularui/widgets/ScrollingTextWidget.java b/src/main/java/brachy/modularui/widgets/ScrollingTextWidget.java index 1408abf..b32929a 100755 --- a/src/main/java/brachy/modularui/widgets/ScrollingTextWidget.java +++ b/src/main/java/brachy/modularui/widgets/ScrollingTextWidget.java @@ -62,9 +62,9 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { animator(new Animator().curve(Interpolation.SINE_INOUT)); } if (this.line == null) { - updateLine(getKey()); + updateLine(checkComponentUpdated()); } - checkString(); + checkComponentUpdated(); WidgetTheme theme = getActiveWidgetTheme(widgetTheme, isHovering()); TextRenderer renderer = TextRenderer.SHARED; renderer.setColor(getColor() != null ? getColor().getAsInt() : theme.getTextColor()); diff --git a/src/main/java/brachy/modularui/widgets/TextWidget.java b/src/main/java/brachy/modularui/widgets/TextWidget.java index 2d22d5a..121bb85 100644 --- a/src/main/java/brachy/modularui/widgets/TextWidget.java +++ b/src/main/java/brachy/modularui/widgets/TextWidget.java @@ -18,20 +18,27 @@ import java.util.Objects; import java.util.function.IntSupplier; +import java.util.function.Supplier; public class TextWidget> extends Widget { - @Getter private final Component key; + @Getter private final Supplier keySupplier; @Getter private Alignment alignment = Alignment.CenterLeft; @Getter private IntSupplier color = null; @Getter private Boolean textShadow = null; @Getter private float scale = 1f; @Getter private int maxWidth = -1; + private Component currentKey; + private String lastText; + public TextWidget(Supplier keySupplier) { + this.keySupplier = keySupplier; + } + public TextWidget(Component key) { - this.key = key; + this(() -> key); } public TextWidget(String key) { @@ -41,7 +48,7 @@ public TextWidget(String key) { @Override public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { TextRenderer renderer = TextRenderer.SHARED; - Component text = checkString(); + Component text = checkComponentUpdated(); WidgetTheme theme = getActiveWidgetTheme(widgetTheme, isHovering()); renderer.setColor(this.color != null ? this.color.getAsInt() : theme.getTextColor()); renderer.setAlignment(this.alignment, getArea().paddedWidth() + this.scale, getArea().paddedHeight()); @@ -52,13 +59,15 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { renderer.draw(context.getGraphics(), text); } - protected Component checkString() { - String text = this.key.getString(); - if (!Objects.equals(this.lastText, text)) { - onTextChanged(this.key); + protected Component checkComponentUpdated() { + var component = keySupplier.get(); + String text = component.getString(); + if (!Objects.equals(currentKey, component) || !Objects.equals(lastText, currentKey.getString())) { + onTextChanged(component); + currentKey = component; this.lastText = text; } - return this.key; + return component; } protected void onTextChanged(Component newText) { @@ -73,7 +82,7 @@ private TextRenderer simulate(float maxWidth) { renderer.setPos(padding.left(), padding.top()); renderer.setScale(this.scale); renderer.setSimulate(true); - renderer.draw(null, this.key); + renderer.draw(null, checkComponentUpdated()); renderer.setSimulate(false); return renderer; } From c8bc64e9fbc115f42ff1385473cb970eff6569f4 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Tue, 5 May 2026 09:51:46 +1000 Subject: [PATCH 6/9] fix recursion error --- .../brachy/modularui/widgets/TextWidget.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/brachy/modularui/widgets/TextWidget.java b/src/main/java/brachy/modularui/widgets/TextWidget.java index 121bb85..f9ccef2 100644 --- a/src/main/java/brachy/modularui/widgets/TextWidget.java +++ b/src/main/java/brachy/modularui/widgets/TextWidget.java @@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -22,23 +23,24 @@ public class TextWidget> extends Widget { - @Getter private final Supplier keySupplier; + @Getter private Component key; @Getter private Alignment alignment = Alignment.CenterLeft; @Getter private IntSupplier color = null; @Getter private Boolean textShadow = null; @Getter private float scale = 1f; @Getter private int maxWidth = -1; - private Component currentKey; - private String lastText; + private final @Nullable Supplier keySupplier; - public TextWidget(Supplier keySupplier) { + public TextWidget(@NotNull Supplier keySupplier) { this.keySupplier = keySupplier; + key = Component.empty(); } public TextWidget(Component key) { - this(() -> key); + this.key = key; + keySupplier = null; } public TextWidget(String key) { @@ -60,14 +62,17 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { } protected Component checkComponentUpdated() { - var component = keySupplier.get(); - String text = component.getString(); - if (!Objects.equals(currentKey, component) || !Objects.equals(lastText, currentKey.getString())) { - onTextChanged(component); - currentKey = component; - this.lastText = text; + if (keySupplier != null) { + var newKey = keySupplier.get(); + if (!Objects.equals(newKey, key)) { + key = newKey; + } + } + if (!Objects.equals(lastText, key.getString())) { + onTextChanged(key); + this.lastText = key.getString(); } - return component; + return key; } protected void onTextChanged(Component newText) { @@ -82,7 +87,8 @@ private TextRenderer simulate(float maxWidth) { renderer.setPos(padding.left(), padding.top()); renderer.setScale(this.scale); renderer.setSimulate(true); - renderer.draw(null, checkComponentUpdated()); + // Don't update the key here, otherwise an infinite loop of checkComponentUpdated -> simulate -> checkComponentUpdated occurs + renderer.draw(null, key); renderer.setSimulate(false); return renderer; } From 40890cb29c2d68654b88aceb546f10e8b69aa010 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Tue, 5 May 2026 09:57:54 +1000 Subject: [PATCH 7/9] fix value init --- src/main/java/brachy/modularui/widgets/TextWidget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/brachy/modularui/widgets/TextWidget.java b/src/main/java/brachy/modularui/widgets/TextWidget.java index f9ccef2..e2c5d52 100644 --- a/src/main/java/brachy/modularui/widgets/TextWidget.java +++ b/src/main/java/brachy/modularui/widgets/TextWidget.java @@ -35,7 +35,7 @@ public class TextWidget> extends Widget { public TextWidget(@NotNull Supplier keySupplier) { this.keySupplier = keySupplier; - key = Component.empty(); + key = keySupplier.get(); } public TextWidget(Component key) { From c60390d753420b1d460bb3d9ffdbd6505b07565c Mon Sep 17 00:00:00 2001 From: Gustavo Date: Wed, 6 May 2026 10:39:12 +1000 Subject: [PATCH 8/9] make text non final --- .../brachy/modularui/widgets/TextWidget.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/brachy/modularui/widgets/TextWidget.java b/src/main/java/brachy/modularui/widgets/TextWidget.java index e2c5d52..660d03c 100644 --- a/src/main/java/brachy/modularui/widgets/TextWidget.java +++ b/src/main/java/brachy/modularui/widgets/TextWidget.java @@ -31,7 +31,7 @@ public class TextWidget> extends Widget { @Getter private int maxWidth = -1; private String lastText; - private final @Nullable Supplier keySupplier; + private @Nullable Supplier keySupplier; public TextWidget(@NotNull Supplier keySupplier) { this.keySupplier = keySupplier; @@ -61,6 +61,21 @@ public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { renderer.draw(context.getGraphics(), text); } + public W value(Supplier textSupplier) { + keySupplier = textSupplier; + return getThis(); + } + + public W value(Component text) { + key = text; + keySupplier = null; + return getThis(); + } + + public W value(String str) { + return value(Text.str(str)); + } + protected Component checkComponentUpdated() { if (keySupplier != null) { var newKey = keySupplier.get(); From b4c811471f7b3d986f0d440812eaa272321a966f Mon Sep 17 00:00:00 2001 From: Gustavo Date: Thu, 7 May 2026 10:03:20 +1000 Subject: [PATCH 9/9] revert test machine change --- src/main/java/brachy/modularui/test/TestMachine.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/brachy/modularui/test/TestMachine.java b/src/main/java/brachy/modularui/test/TestMachine.java index b07d2c3..e787d29 100644 --- a/src/main/java/brachy/modularui/test/TestMachine.java +++ b/src/main/java/brachy/modularui/test/TestMachine.java @@ -292,7 +292,6 @@ public static IWidget buildMachineUI(IItemHandler in, IItemHandler out, IDoubleV public static IWidget buildViewerUI(Recipe recipe) { return Flow.row().name("slots") - .coverChildren() .center() .childPadding(8) .child(SlotGroupWidget.rect(2, 2, i -> { @@ -300,7 +299,7 @@ public static IWidget buildViewerUI(Recipe recipe) { if (in == null) in = ItemStack.EMPTY; return RecipeViewerSlotWidget.create() .recipeSlotRole(RecipeSlotRole.INPUT) - .value(FluidStackList.of(List.of(new FluidStack(Fluids.LAVA, 1000), new FluidStack(Fluids.WATER, 100)))); + .value(in); })) .child(new ProgressWidget() .value(DoubleValue.simulateProgress(5000))