From e4e61025dc25eefec3dfd419a5c9f0a11000e163 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 26 Jun 2022 21:45:36 +0800 Subject: Primitive tags category implementation --- .../rei/api/client/gui/widgets/Widget.java | 2 +- .../rei/api/client/gui/widgets/Widgets.java | 19 +++- .../me/shedaniel/rei/impl/ClientInternals.java | 6 +- .../client/categories/tag/DefaultTagCategory.java | 38 +++---- .../categories/tag/ReferenceTagNodeWidget.java | 83 ++++++++++++++ .../client/categories/tag/TagNodeWidget.java | 43 ++++++++ .../client/categories/tag/TagTreeWidget.java | 122 +++++++++++++++++++++ .../client/categories/tag/TagTreesWidget.java | 48 ++++++++ .../client/categories/tag/ValueTagNodeWidget.java | 103 +++++++++++++++++ .../common/displays/tag/DefaultTagDisplay.java | 4 + .../rei/plugin/common/displays/tag/TagNode.java | 58 +++++----- .../rei/plugin/common/displays/tag/TagNodes.java | 7 +- .../gui/screen/AbstractDisplayViewingScreen.java | 5 + .../gui/widget/DelegateWidgetWithTranslate.java | 17 ++- .../impl/client/gui/widget/InternalWidgets.java | 15 ++- .../rei/impl/client/gui/widget/NoOpWidget.java | 10 +- .../rei/impl/client/gui/widget/OverflowWidget.java | 30 ++--- .../impl/client/gui/widget/PaddedCenterWidget.java | 58 ++++++++++ .../rei/impl/client/gui/widget/PaddedWidget.java | 51 +++++++++ 19 files changed, 639 insertions(+), 80 deletions(-) create mode 100644 default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java create mode 100644 default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagNodeWidget.java create mode 100644 default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreeWidget.java create mode 100644 default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreesWidget.java create mode 100644 default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java index 1c70c616d..df350c9c7 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java @@ -85,7 +85,7 @@ public abstract class Widget extends AbstractContainerEventHandler implements ne Point mouse = mouse(); Vector4f mouseVec = new Vector4f(mouse.x, mouse.y, 0, 1); mouseVec.transform(pose); - return pushMouse(mouse); + return pushMouse(new Point(mouseVec.x(), mouseVec.y())); } public int getZ() { 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 33adcde29..eb1f54d7d 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 @@ -303,15 +303,30 @@ public final class Widgets { return ClientInternals.getWidgetsProvider().concatWidgets(widgets); } - public static Widget noOp() { + public static WidgetWithBounds noOp() { return ClientInternals.getWidgetsProvider().noOp(); } @ApiStatus.Experimental - public static Widget overflowed(Rectangle bounds, WidgetWithBounds widget) { + public static WidgetWithBounds overflowed(Rectangle bounds, WidgetWithBounds widget) { return ClientInternals.getWidgetsProvider().wrapOverflow(bounds, widget); } + @ApiStatus.Experimental + public static WidgetWithBounds padded(int padding, WidgetWithBounds widget) { + return padded(padding, padding, padding, padding, widget); + } + + @ApiStatus.Experimental + public static WidgetWithBounds padded(int padX, int padY, WidgetWithBounds widget) { + return padded(padX, padX, padY, padY, widget); + } + + @ApiStatus.Experimental + public static WidgetWithBounds padded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { + return ClientInternals.getWidgetsProvider().wrapPadded(padLeft, padRight, padTop, padBottom, widget); + } + 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 f68d28e95..36456399b 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java @@ -201,8 +201,10 @@ public final class ClientInternals { Widget concatWidgets(List widgets); - Widget noOp(); + WidgetWithBounds noOp(); - Widget wrapOverflow(Rectangle bounds, WidgetWithBounds widget); + WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget); + + WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget); } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java index 07d5fe985..49ebb91ca 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java @@ -26,7 +26,7 @@ package me.shedaniel.rei.plugin.client.categories.tag; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.api.client.gui.widgets.DelegateWidget; +import me.shedaniel.rei.api.client.gui.widgets.DelegateWidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; @@ -38,8 +38,6 @@ import me.shedaniel.rei.plugin.common.displays.tag.DefaultTagDisplay; import me.shedaniel.rei.plugin.common.displays.tag.TagNode; import me.shedaniel.rei.plugin.common.displays.tag.TagNodes; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; @@ -73,39 +71,31 @@ public class DefaultTagCategory implements DisplayCategory[] tagNode = new TagNode[]{null}; Rectangle overflowBounds = new Rectangle(innerBounds.x + 1, innerBounds.y + 1, innerBounds.width - 2, innerBounds.height - 2); - WidgetWithBounds inner = Widgets.withBounds(new DelegateWidget(Widgets.noOp()) { + widgets.add(Widgets.withTranslate(Widgets.overflowed(overflowBounds, new DelegateWidgetWithBounds(Widgets.noOp(), Rectangle::new) { @Override - protected Widget delegate() { + protected WidgetWithBounds delegate() { return delegate[0]; } - }, overflowBounds); - widgets.add(Widgets.withTranslate(Widgets.overflowed(overflowBounds, Widgets.withBounds(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - new GuiComponent() { - { - fillGradient(matrices, 0, 0, 1000, 1000, 0xff3489eb, 0xffc41868); - for (int x = 0; x < 10; x++) { - for (int y = 0; y < 10; y++) { - Widgets.createSlot(new Point(500 - 9 * 10 + x * 18, 500 - 9 * 10 + y * 18)) - .entry(EntryStacks.of(Registry.ITEM.byId(x + y * 10 + 1))) - .disableBackground() - .render(matrices, mouseX, mouseY, delta); - } - } - } - }; - }), new Rectangle(0, 0, 1000, 1000))), 0, 0, 20)); + + @Override + public Rectangle getBounds() { + return delegate().getBounds(); + } + }), 0, 0, 20)); TagNodes.create(display.getKey(), dataResult -> { if (dataResult.error().isPresent()) { - delegate[0] = Widgets.concat( + delegate[0] = Widgets.withBounds(Widgets.concat( Widgets.createLabel(new Point(innerBounds.getCenterX(), innerBounds.getCenterY() - 8), new TextComponent("Failed to resolve tags!")), Widgets.createLabel(new Point(innerBounds.getCenterX(), innerBounds.getCenterY() - 8), new TextComponent(dataResult.error().get().message())) - ); + ), overflowBounds); } else { tagNode[0] = dataResult.result().get(); + //noinspection rawtypes + delegate[0] = Widgets.padded(16, new TagTreeWidget(tagNode[0], display.getMapper())); } }); diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java new file mode 100644 index 000000000..75beaf41c --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java @@ -0,0 +1,83 @@ +/* + * 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.client.categories.tag; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryIngredients; +import me.shedaniel.rei.plugin.common.displays.tag.TagNode; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +public class ReferenceTagNodeWidget extends TagNodeWidget { + private final TagNode node; + private final Rectangle bounds; + private final Slot slot; + private final List children; + + public ReferenceTagNodeWidget(TagNode node, Function, EntryStack> mapper) { + this.node = node; + this.bounds = new Rectangle(0, 0, 24, 23); + this.slot = Widgets.createSlot(new Rectangle(0, 0, 18, 18)) + .disableBackground() + .disableHighlight() + .disableTooltips() + .entries(EntryIngredients.ofTag(node.getReference(), mapper)); + this.children = Collections.singletonList(this.slot); + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, new ResourceLocation("textures/gui/advancements/widgets.png")); + this.blit(poses, bounds.x, bounds.y, 1, 128 + 27, 24, 24); + this.slot.getBounds().setLocation(bounds.getCenterX() - this.slot.getBounds().getWidth() / 2, bounds.y + (bounds.height - this.slot.getBounds().getHeight()) / 2 + 1); + this.slot.render(poses, mouseX, mouseY, delta); + if (this.containsMouse(mouseX, mouseY)) { + Tooltip.create(new TextComponent("#" + this.node.getReference().location().toString())).queue(); + } + } + + @Override + public List children() { + return children; + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagNodeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagNodeWidget.java new file mode 100644 index 000000000..9f2216935 --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagNodeWidget.java @@ -0,0 +1,43 @@ +/* + * 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.client.categories.tag; + +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.plugin.common.displays.tag.TagNode; +import net.minecraft.core.Holder; + +import java.util.function.Function; + +public abstract class TagNodeWidget extends WidgetWithBounds { + static TagNodeWidget create(TagNode node, Function, EntryStack> mapper) { + if (node.getReference() != null) { + return new ReferenceTagNodeWidget<>(node, mapper); + } else if (node.getValue() != null) { + return new ValueTagNodeWidget<>(node, mapper); + } else { + throw new IllegalArgumentException("TagNode has no value or reference"); + } + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreeWidget.java new file mode 100644 index 000000000..f544d4d7f --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreeWidget.java @@ -0,0 +1,122 @@ +/* + * 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.client.categories.tag; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Color; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.plugin.common.displays.tag.TagNode; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.core.Holder; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Stream; + +public class TagTreeWidget extends WidgetWithBounds { + private final Rectangle bounds; + private final TagNode node; + private final TagNodeWidget rootWidget; + private final List> childWidgets; + private final List children; + + public TagTreeWidget(TagNode node, Function, EntryStack> mapper) { + this.node = node; + this.rootWidget = TagNodeWidget.create(node, mapper); + this.childWidgets = new ArrayList<>(); + for (TagNode childNode : node.children()) { + TagTreeWidget childWidget = new TagTreeWidget<>(childNode, mapper); + childWidget.getBounds().y = rootWidget.getBounds().getMaxY() + 16; + this.childWidgets.add(childWidget); + } + int childrenTotalWidth = childWidgets.stream().map(WidgetWithBounds::getBounds).mapToInt(value -> value.width + 6).sum() - 6; + int x = 0; + for (TagTreeWidget childWidget : this.childWidgets) { + childWidget.getBounds().x = rootWidget.getBounds().getCenterX() - childrenTotalWidth / 2 + x; + x += childWidget.getBounds().width + 6; + } + this.children = Stream.concat(Stream.of(this.rootWidget), this.childWidgets.stream()).toList(); + this.bounds = new Rectangle(this.children.stream() + .map(WidgetWithBounds::getBounds) + .reduce(Rectangle::union) + .orElse(new Rectangle()) + .getSize()); + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + this.rootWidget.getBounds().setLocation(getBounds().getCenterX() - this.rootWidget.getBounds().getWidth() / 2, + getBounds().y); + this.rootWidget.render(poses, mouseX, mouseY, delta); + if (childWidgets.isEmpty()) return; + vLine(poses, rootWidget.getBounds().getCenterX(), rootWidget.getBounds().getMaxY(), rootWidget.getBounds().getMaxY() + 6, 0xFFFFFFFF); + int childrenTotalWidth = childWidgets.stream().map(WidgetWithBounds::getBounds).mapToInt(value -> value.width + 6).sum() - 6; + hLine(poses, rootWidget.getBounds().getCenterX() - childrenTotalWidth / 2 + childWidgets.get(0).getBounds().width / 2, + rootWidget.getBounds().getCenterX() + childrenTotalWidth / 2 - childWidgets.get(childWidgets.size() - 1).getBounds().width / 2, + rootWidget.getBounds().getMaxY() + 6, 0xFFFFFFFF); + int x = 0; + for (TagTreeWidget childWidget : this.childWidgets) { + vLine(poses, getBounds().getCenterX() - childrenTotalWidth / 2 + x + childWidget.getBounds().width / 2, + rootWidget.getBounds().getMaxY() + 6, rootWidget.getBounds().getMaxY() + 16, 0xFFFFFFFF); + childWidget.getBounds().setLocation(getBounds().getCenterX() - childrenTotalWidth / 2 + x, + this.rootWidget.getBounds().getMaxY() + 16); + childWidget.render(poses, mouseX, mouseY, delta); + x += childWidget.getBounds().width + 6; + } + } + + @Override + public List children() { + return children; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + for (GuiEventListener element : children()) + if (element.mouseReleased(mouseX, mouseY, button)) + return true; + return false; + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + for (GuiEventListener element : children()) + if (element.keyPressed(keyCode, scanCode, modifiers)) + return true; + return false; + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreesWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreesWidget.java new file mode 100644 index 000000000..bfa0a0e56 --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/TagTreesWidget.java @@ -0,0 +1,48 @@ +/* + * 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.client.categories.tag; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import net.minecraft.client.gui.components.events.GuiEventListener; + +import java.util.List; + +public class TagTreesWidget extends WidgetWithBounds { + @Override + public Rectangle getBounds() { + return null; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + + } + + @Override + public List children() { + return null; + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java new file mode 100644 index 000000000..677c4cd1d --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java @@ -0,0 +1,103 @@ +/* + * 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.client.categories.tag; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryIngredients; +import me.shedaniel.rei.plugin.common.displays.tag.TagNode; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.util.Mth; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +public class ValueTagNodeWidget extends TagNodeWidget { + private final Rectangle bounds; + private final WidgetWithBounds widget; + private final List children; + + public ValueTagNodeWidget(TagNode node, Function, EntryStack> mapper) { + HolderSet holders = node.getValue(); + int width = Math.min(4, holders.size()); + int height = Math.max((int) Math.ceil(holders.size() * 1.0 / width), 1); + this.bounds = new Rectangle(0, 0, 16 * width + 12, 16 * height + 12); + Panel background = Widgets.createRecipeBase(bounds.clone()); + Panel slotBackground = Widgets.createSlotBase(new Rectangle(5, 5, 16 * width + 2, 16 * height + 2)); + int i = 0; + List widgets = new ArrayList<>(); + widgets.add(background); + widgets.add(slotBackground); + for (Holder holder : holders) { + int x = i % width; + int y = i / width; + Slot slot = Widgets.createSlot(new Rectangle(x * 16 + 5, y * 16 + 5, 18, 18)) + .entry(mapper.apply(holder)) + .disableBackground(); + widgets.add(slot); + i++; + } + this.widget = Widgets.withTranslate(Widgets.concat(widgets), + $ -> Matrix4f.createTranslateMatrix(getBounds().x, getBounds().y, 0)); + this.children = Collections.singletonList(this.widget); + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + this.widget.render(poses, mouseX, mouseY, delta); + } + + @Override + public List children() { + return children; + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + for (GuiEventListener element : children()) + if (element.mouseReleased(mouseX, mouseY, button)) + return true; + return false; + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + for (GuiEventListener element : children()) + if (element.keyPressed(keyCode, scanCode, modifiers)) + return true; + return false; + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/DefaultTagDisplay.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/DefaultTagDisplay.java index 09c453019..6b070eded 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/DefaultTagDisplay.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/DefaultTagDisplay.java @@ -95,4 +95,8 @@ public class DefaultTagDisplay implements Display { public TagKey getKey() { return key; } + + public Function, EntryStack> getMapper() { + return mapper; + } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNode.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNode.java index 94b5b047d..2dc2d0265 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNode.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNode.java @@ -24,14 +24,14 @@ package me.shedaniel.rei.plugin.common.displays.tag; import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @ApiStatus.Internal public abstract class TagNode { @@ -41,8 +41,8 @@ public abstract class TagNode { this.children = new ArrayList<>(); } - public static TagNode ofValue(Holder value) { - return new ValueTagNode<>(value); + public static TagNode ofValues(HolderSet value) { + return new ValuesTagNode<>(value); } public static TagNode ofReference(TagKey key) { @@ -57,8 +57,8 @@ public abstract class TagNode { children.add(child); } - public void addValueChild(Holder child) { - children.add(ofValue(child)); + public void addValuesChild(HolderSet child) { + children.add(ofValues(child)); } public void addReferenceChild(TagKey child) { @@ -66,29 +66,27 @@ public abstract class TagNode { } public String asTree() { - StringBuilder buffer = new StringBuilder(50); - printTree(buffer, "", ""); - return buffer.toString(); + StringBuilder builder = new StringBuilder(50); + printTree(builder, "", ""); + return builder.toString(); } - private void printTree(StringBuilder buffer, String prefix, String childrenPrefix) { - buffer.append(prefix); - buffer.append(asText()); - buffer.append('\n'); + private void printTree(StringBuilder builder, String prefix, String childrenPrefix) { + asText(prefix, builder); for (Iterator> it = children.iterator(); it.hasNext(); ) { TagNode next = it.next(); if (it.hasNext()) { - next.printTree(buffer, childrenPrefix + "├── ", childrenPrefix + "│ "); + next.printTree(builder, childrenPrefix + "├── ", childrenPrefix + "│ "); } else { - next.printTree(buffer, childrenPrefix + "└── ", childrenPrefix + " "); + next.printTree(builder, childrenPrefix + "└── ", childrenPrefix + " "); } } } - protected abstract String asText(); + protected abstract void asText(String prefix, StringBuilder builder); @Nullable - public Holder getValue() { + public HolderSet getValue() { return null; } @@ -97,21 +95,27 @@ public abstract class TagNode { return null; } - private static class ValueTagNode extends TagNode { - private final Holder value; + private static class ValuesTagNode extends TagNode { + private final HolderSet value; - public ValueTagNode(Holder value) { + public ValuesTagNode(HolderSet value) { this.value = value; } @Override - public Holder getValue() { + public HolderSet getValue() { return value; } @Override - protected String asText() { - return value.unwrapKey().map(ResourceKey::location).orElse(null) + ""; + protected void asText(String prefix, StringBuilder builder) { + for (Holder holder : value) { + holder.unwrapKey().ifPresent(key -> { + builder.append(prefix); + builder.append(key.location().toString()); + builder.append('\n'); + }); + } } } @@ -128,8 +132,10 @@ public abstract class TagNode { } @Override - protected String asText() { - return key.location() + ""; + protected void asText(String prefix, StringBuilder builder) { + builder.append(prefix); + builder.append(key.location()); + builder.append('\n'); } } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNodes.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNodes.java index 832249cc2..163776b87 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNodes.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/tag/TagNodes.java @@ -36,6 +36,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceKey; @@ -187,12 +188,16 @@ public class TagNodes { if (tagData == null) return DataResult.error("Tag Missing: " + tagKey.location()); TagNode self = TagNode.ofReference(tagKey); + List> holders = new ArrayList<>(); for (int element : tagData.otherElements()) { Optional> holder = registry.getHolder(element); if (holder.isPresent()) { - self.addValueChild(holder.get()); + holders.add(holder.get()); } } + if (!holders.isEmpty()) { + self.addValuesChild(HolderSet.direct(holders)); + } for (ResourceLocation childTagId : tagData.otherTags()) { TagKey childTagKey = TagKey.create(tagKey.registry(), childTagId); if (registry.getTag(childTagKey).isPresent()) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java index 7c6a0eeda..e0b06e2f3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java @@ -367,6 +367,11 @@ public abstract class AbstractDisplayViewingScreen extends Screen implements Dis return super.mouseScrolled(mouseX, mouseY, amount) || (getOverlay().mouseScrolled(mouseX, mouseY, amount) && handleFocuses()); } + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + return super.keyPressed(keyCode, scanCode, modifiers) || (getOverlay().keyPressed(keyCode, scanCode, modifiers) && handleFocuses()); + } + @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { return super.keyReleased(keyCode, scanCode, modifiers) || (getOverlay().keyReleased(keyCode, scanCode, modifiers) && handleFocuses()); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java index c3e2090cd..582a01830 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java @@ -25,6 +25,8 @@ package me.shedaniel.rei.impl.client.gui.widget; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; import com.mojang.math.Vector4f; import me.shedaniel.rei.api.client.gui.widgets.DelegateWidget; import me.shedaniel.rei.api.client.gui.widgets.Widget; @@ -44,6 +46,13 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { return translate.get(); } + protected final Matrix4f inverseTranslate() { + Transformation transformation = new Transformation(translate()); + Transformation inverse = transformation.inverse(); + if (inverse != null) inverse.getScale(); // This has a side effect + return inverse == null ? Transformation.identity().getMatrix() : inverse.getMatrix(); + } + @Override public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { poseStack.pushPose(); @@ -55,7 +64,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { private Vector4f transformMouse(double mouseX, double mouseY) { Vector4f mouse = new Vector4f((float) mouseX, (float) mouseY, 0, 1); - mouse.transform(translate()); + mouse.transform(inverseTranslate()); return mouse; } @@ -92,7 +101,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { try { - Widget.translateMouse(translate()); + Widget.translateMouse(inverseTranslate()); return super.keyPressed(keyCode, scanCode, modifiers); } finally { Widget.popMouse(); @@ -102,7 +111,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { try { - Widget.translateMouse(translate()); + Widget.translateMouse(inverseTranslate()); return super.keyReleased(keyCode, scanCode, modifiers); } finally { Widget.popMouse(); @@ -112,7 +121,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { @Override public boolean charTyped(char character, int modifiers) { try { - Widget.translateMouse(translate()); + Widget.translateMouse(inverseTranslate()); return super.charTyped(character, modifiers); } finally { Widget.popMouse(); 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 92004f529..afab2362e 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 @@ -78,7 +78,7 @@ public final class InternalWidgets { if (result.hasApplicable) { autoCraftingButton.setText(text); } else { - autoCraftingButton.setText(new TextComponent("?")); + autoCraftingButton.setText(new TextComponent("!")); } if (result.hasApplicable && (containsMouse(mouseX, mouseY) || autoCraftingButton.isFocused()) && result.renderer != null) { @@ -270,13 +270,18 @@ public final class InternalWidgets { } @Override - public Widget noOp() { + public WidgetWithBounds noOp() { return NoOpWidget.INSTANCE; } - + + @Override + public WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget) { + return new OverflowWidget(bounds, new PaddedCenterWidget(bounds, widget)); + } + @Override - public Widget wrapOverflow(Rectangle bounds, WidgetWithBounds widget) { - return new OverflowWidget(bounds, widget); + public WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { + return new PaddedWidget(padLeft, padRight, padTop, padBottom, widget); } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java index a9cfd79ce..b31c61532 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java @@ -24,13 +24,14 @@ package me.shedaniel.rei.impl.client.gui.widget; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.math.Rectangle; +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; -public class NoOpWidget extends Widget { +public class NoOpWidget extends WidgetWithBounds { public static final NoOpWidget INSTANCE = new NoOpWidget(); private NoOpWidget() { @@ -44,4 +45,9 @@ public class NoOpWidget extends Widget { public List children() { return Collections.emptyList(); } + + @Override + public Rectangle getBounds() { + return new Rectangle(); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java index 89fca306e..b46640493 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java @@ -25,7 +25,6 @@ package me.shedaniel.rei.impl.client.gui.widget; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; -import me.shedaniel.clothconfig2.api.ScissorsHandler; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; @@ -34,9 +33,6 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.gui.widgets.CloseableScissors; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.impl.common.util.RectangleUtils; - -import java.io.Closeable; @SuppressWarnings("UnstableApiUsage") public class OverflowWidget extends DelegateWidgetWithTranslate { @@ -70,15 +66,17 @@ public class OverflowWidget extends DelegateWidgetWithTranslate { public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { Rectangle widgetBounds = ((WidgetWithBounds) widget).getBounds(); this.scale.update(delta); - this.scale.setTarget(ScrollingContainer.handleBounceBack(this.scale.target() - 1, - Math.min(widgetBounds.width * 1.0F / getBounds().width, widgetBounds.height * 1.0F / getBounds().height) - 1, delta, .001) + 1); + this.scale.setTarget(ScrollingContainer.handleBounceBack(this.scale.target() - 0.78, + Math.min(widgetBounds.width * 1.0F / getBounds().width, widgetBounds.height * 1.0F / getBounds().height) - 0.78, delta, .001) + 0.78); this.translate.update(delta); - this.translate.setAs(new FloatingPoint( - ScrollingContainer.handleBounceBack(this.translate.target().x + widgetBounds.width - getBounds().width / 2 * scale.value(), - widgetBounds.width - getBounds().width * scale.value(), delta, .001) - (widgetBounds.width - getBounds().width / 2 * scale.value()), - ScrollingContainer.handleBounceBack(this.translate.target().y + widgetBounds.height - getBounds().height / 2 * scale.value(), - widgetBounds.height - getBounds().height * scale.value(), delta, .001) - (widgetBounds.height - getBounds().height / 2 * scale.value()) - )); + for (int i = 0; i < 3; i++) { + this.translate.setAs(new FloatingPoint( + ScrollingContainer.handleBounceBack(this.translate.target().x + widgetBounds.width - getBounds().width / 2 * scale.value(), + widgetBounds.width - getBounds().width * scale.value(), delta, .0001) - (widgetBounds.width - getBounds().width / 2 * scale.value()), + ScrollingContainer.handleBounceBack(this.translate.target().y + widgetBounds.height - getBounds().height / 2 * scale.value(), + widgetBounds.height - getBounds().height * scale.value(), delta, .0001) - (widgetBounds.height - getBounds().height / 2 * scale.value()) + )); + } if (!RoughlyEnoughItemsCoreClient.isLeftMousePressed) { this.translate.setAs(new FloatingPoint(this.translate.value().x + this.velocity.value().x, this.translate.value().y + this.velocity.value().y)); } @@ -89,7 +87,13 @@ public class OverflowWidget extends DelegateWidgetWithTranslate { ), 20); try (CloseableScissors scissors = scissor(poseStack, this.bounds)) { - super.render(poseStack, mouseX, mouseY, delta); + boolean containsMouse = this.bounds.contains(mouseX, mouseY); + + if (containsMouse) { + super.render(poseStack, mouseX, mouseY, delta); + } else { + super.render(poseStack, Integer.MAX_VALUE, Integer.MAX_VALUE, delta); + } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java new file mode 100644 index 000000000..7848fa7f0 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java @@ -0,0 +1,58 @@ +/* + * 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.math.Matrix4f; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; + +public class PaddedCenterWidget extends DelegateWidgetWithTranslate { + private final Rectangle bounds; + + public PaddedCenterWidget(Rectangle bounds, WidgetWithBounds widget) { + super(widget, Matrix4f::new); + this.bounds = bounds; + } + + @Override + protected Matrix4f translate() { + Rectangle widgetBounds = ((WidgetWithBounds) widget).getBounds(); + float xTranslate = 0, yTranslate = 0; + if (widgetBounds.width < bounds.width) { + xTranslate = (bounds.width - widgetBounds.width) / 2f; + } + if (widgetBounds.height < bounds.height) { + yTranslate = (bounds.height - widgetBounds.height) / 2f; + } + return Matrix4f.createTranslateMatrix(xTranslate, yTranslate, 0); + } + + @Override + public Rectangle getBounds() { + Rectangle widgetBounds = ((WidgetWithBounds) widget).getBounds(); + int newWidth = Math.max(widgetBounds.width, bounds.width); + int newHeight = Math.max(widgetBounds.height, bounds.height); + return new Rectangle(bounds.getCenterX() - newWidth / 2f, bounds.getCenterY() - newHeight / 2f, newWidth, newHeight); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java new file mode 100644 index 000000000..4151ffb45 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java @@ -0,0 +1,51 @@ +/* + * 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.math.Matrix4f; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; + +public class PaddedWidget extends DelegateWidgetWithTranslate { + private final int padLeft, padRight, padTop, padBottom; + + public PaddedWidget(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { + super(widget, Matrix4f::new); + this.padLeft = padLeft; + this.padRight = padRight; + this.padTop = padTop; + this.padBottom = padBottom; + } + + @Override + protected Matrix4f translate() { + return Matrix4f.createTranslateMatrix(padLeft, padRight, 0); + } + + @Override + public Rectangle getBounds() { + Rectangle widgetBounds = ((WidgetWithBounds) widget).getBounds(); + return new Rectangle(widgetBounds.x - padLeft, widgetBounds.y - padTop, widgetBounds.width + padLeft + padRight, widgetBounds.height + padTop + padBottom); + } +} -- cgit