From 81b82416abb2a94c12638fdbb08df2ac0f83254f Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 26 Jun 2022 03:33:14 +0800 Subject: WIP on Tag Category, add Overflow Widget --- .../rei/RoughlyEnoughItemsCoreClient.java | 15 ++- .../gui/screen/AbstractDisplayViewingScreen.java | 52 ++++++++ .../gui/widget/DelegateWidgetWithTranslate.java | 44 +++--- .../impl/client/gui/widget/InternalWidgets.java | 5 + .../rei/impl/client/gui/widget/NoOpWidget.java | 23 ++++ .../rei/impl/client/gui/widget/OverflowWidget.java | 148 +++++++++++++++++++++ 6 files changed, 260 insertions(+), 27 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index af0407f3d..a546bb033 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -38,6 +38,7 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; @@ -365,7 +366,7 @@ public class RoughlyEnoughItemsCoreClient { }); ClientScreenInputEvent.MOUSE_CLICKED_PRE.register((minecraftClient, screen, mouseX, mouseY, button) -> { isLeftMousePressed = true; - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); if (getOverlay().mouseClicked(mouseX, mouseY, button)) { @@ -379,7 +380,7 @@ public class RoughlyEnoughItemsCoreClient { }); ClientScreenInputEvent.MOUSE_RELEASED_PRE.register((minecraftClient, screen, mouseX, mouseY, button) -> { isLeftMousePressed = false; - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); if (REIRuntime.getInstance().isOverlayVisible() && getOverlay().mouseReleased(mouseX, mouseY, button) @@ -389,7 +390,7 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.pass(); }); ClientScreenInputEvent.MOUSE_SCROLLED_PRE.register((minecraftClient, screen, mouseX, mouseY, amount) -> { - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); if (REIRuntime.getInstance().isOverlayVisible() && getOverlay().mouseScrolled(mouseX, mouseY, amount) @@ -398,7 +399,7 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.pass(); }); ClientScreenInputEvent.CHAR_TYPED_PRE.register((minecraftClient, screen, character, keyCode) -> { - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) if (!REIRuntimeImpl.getSearchField().isFocused()) @@ -418,7 +419,7 @@ public class RoughlyEnoughItemsCoreClient { resetFocused(screen); }); ClientScreenInputEvent.MOUSE_DRAGGED_PRE.register((minecraftClient, screen, mouseX1, mouseY1, button, mouseX2, mouseY2) -> { - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); if (getOverlay().mouseDragged(mouseX1, mouseY1, button, mouseX2, mouseY2) @@ -427,7 +428,7 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.pass(); }); ClientScreenInputEvent.KEY_PRESSED_PRE.register((minecraftClient, screen, i, i1, i2) -> { - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); if (screen instanceof AbstractContainerScreen && ConfigObject.getInstance().doesDisableRecipeBook() && ConfigObject.getInstance().doesFixTabCloseContainer()) { if (i == 258 && minecraftClient.options.keyInventory.matches(i, i1)) { @@ -445,7 +446,7 @@ public class RoughlyEnoughItemsCoreClient { return EventResult.pass(); }); ClientScreenInputEvent.KEY_RELEASED_PRE.register((minecraftClient, screen, i, i1, i2) -> { - if (shouldReturn(screen)) + if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) if (!REIRuntimeImpl.getSearchField().isFocused()) 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 1ae89bdf1..7c6a0eeda 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 @@ -30,11 +30,13 @@ import com.mojang.datafixers.util.Pair; import com.mojang.math.Matrix4f; import dev.architectury.fluid.FluidStack; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; 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.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.registry.display.DisplayCategoryView; @@ -324,4 +326,54 @@ public abstract class AbstractDisplayViewingScreen extends Screen implements Dis widget.tooltipProcessor(new TooltipProcessor()); } + + private static ScreenOverlay getOverlay() { + return REIRuntime.getInstance().getOverlay().orElseThrow(() -> new IllegalStateException("Overlay not initialized!")); + } + + private boolean handleFocuses(int button) { + if (button == 0) { + setDragging(true); + } + handleFocuses(); + return true; + } + + private boolean handleFocuses() { + if (getFocused() instanceof ScreenOverlay || getFocused() == this) { + setFocused(null); + } + + return true; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return super.mouseClicked(mouseX, mouseY, button) || (getOverlay().mouseClicked(mouseX, mouseY, button) && handleFocuses()); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return super.mouseReleased(mouseX, mouseY, button) || (getOverlay().mouseReleased(mouseX, mouseY, button) && handleFocuses()); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY) || (getOverlay().mouseDragged(mouseX, mouseY, button, deltaX, deltaY) && handleFocuses()); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + return super.mouseScrolled(mouseX, mouseY, amount) || (getOverlay().mouseScrolled(mouseX, mouseY, amount) && handleFocuses()); + } + + @Override + public boolean keyReleased(int keyCode, int scanCode, int modifiers) { + return super.keyReleased(keyCode, scanCode, modifiers) || (getOverlay().keyReleased(keyCode, scanCode, modifiers) && handleFocuses()); + } + + @Override + public boolean charTyped(char character, int modifiers) { + return super.charTyped(character, modifiers) || (getOverlay().charTyped(character, 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 c03cd3fb3..c3e2090cd 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 @@ -40,18 +40,22 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { this.translate = translate; } + protected Matrix4f translate() { + return translate.get(); + } + @Override - public void render(PoseStack poseStack, int i, int j, float f) { + public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { poseStack.pushPose(); - poseStack.last().pose().multiply(translate.get()); - Vector4f mouse = transformMouse(i, j); - super.render(poseStack, (int) mouse.x(), (int) mouse.y(), f); + poseStack.last().pose().multiply(translate()); + Vector4f mouse = transformMouse(mouseX, mouseY); + super.render(poseStack, (int) mouse.x(), (int) mouse.y(), delta); poseStack.popPose(); } private Vector4f transformMouse(double mouseX, double mouseY) { Vector4f mouse = new Vector4f((float) mouseX, (float) mouseY, 0, 1); - mouse.transform(translate.get()); + mouse.transform(translate()); return mouse; } @@ -62,33 +66,33 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { } @Override - public boolean mouseClicked(double d, double e, int i) { - Vector4f mouse = transformMouse(d, e); - return super.mouseClicked(mouse.x(), mouse.y(), i); + public boolean mouseClicked(double mouseX, double mouseY, int button) { + Vector4f mouse = transformMouse(mouseX, mouseY); + return super.mouseClicked(mouse.x(), mouse.y(), button); } @Override - public boolean mouseReleased(double d, double e, int i) { - Vector4f mouse = transformMouse(d, e); - return super.mouseReleased(mouse.x(), mouse.y(), i); + public boolean mouseReleased(double mouseX, double mouseY, int button) { + Vector4f mouse = transformMouse(mouseX, mouseY); + return super.mouseReleased(mouse.x(), mouse.y(), button); } @Override - public boolean mouseDragged(double d, double e, int i, double f, double g) { - Vector4f mouse = transformMouse(d, e); - return super.mouseDragged(mouse.x(), mouse.y(), i, f, g); + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + Vector4f mouse = transformMouse(mouseX, mouseY); + return super.mouseDragged(mouse.x(), mouse.y(), button, deltaX, deltaY); } @Override - public boolean mouseScrolled(double d, double e, double f) { - Vector4f mouse = transformMouse(d, e); - return super.mouseScrolled(mouse.x(), mouse.y(), f); + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + Vector4f mouse = transformMouse(mouseX, mouseY); + return super.mouseScrolled(mouse.x(), mouse.y(), amount); } @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { try { - Widget.translateMouse(translate.get()); + Widget.translateMouse(translate()); return super.keyPressed(keyCode, scanCode, modifiers); } finally { Widget.popMouse(); @@ -98,7 +102,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { try { - Widget.translateMouse(translate.get()); + Widget.translateMouse(translate()); return super.keyReleased(keyCode, scanCode, modifiers); } finally { Widget.popMouse(); @@ -108,7 +112,7 @@ public class DelegateWidgetWithTranslate extends DelegateWidget { @Override public boolean charTyped(char character, int modifiers) { try { - Widget.translateMouse(translate.get()); + Widget.translateMouse(translate()); 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 a4dafd5bd..92004f529 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 @@ -273,5 +273,10 @@ public final class InternalWidgets { public Widget noOp() { return NoOpWidget.INSTANCE; } + + @Override + public Widget wrapOverflow(Rectangle bounds, WidgetWithBounds widget) { + return new OverflowWidget(bounds, 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 a682b83e5..a9cfd79ce 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 @@ -1,3 +1,26 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.shedaniel.rei.impl.client.gui.widget; import com.mojang.blaze3d.vertex.PoseStack; 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 new file mode 100644 index 000000000..12cdfcfc9 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java @@ -0,0 +1,148 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.client.gui.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import 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; +import me.shedaniel.math.FloatingPoint; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; +import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; + +@SuppressWarnings("UnstableApiUsage") +public class OverflowWidget extends DelegateWidgetWithTranslate { + private final Rectangle bounds; + private final NumberAnimator scale; + private final ValueAnimator translate; + private final ValueAnimator velocity; + private boolean dragging; + + public OverflowWidget(Rectangle bounds, WidgetWithBounds widget) { + super(widget, Matrix4f::new); + this.bounds = bounds; + this.scale = ValueAnimator.ofFloat() + .setAs(1f); + this.translate = ValueAnimator.ofFloatingPoint() + .setAs(new FloatingPoint(-widget.getBounds().width / 2f, -widget.getBounds().height / 2f)); + this.velocity = ValueAnimator.ofFloatingPoint() + .setAs(new FloatingPoint(0f, 0f)); + } + + @Override + protected Matrix4f translate() { + FloatingPoint translate = this.translate.value(); + float scale = 1 / Math.max(this.scale.floatValue(), 0.001f); + Matrix4f matrix = Matrix4f.createTranslateMatrix(bounds.getCenterX() + (float) translate.x * scale, bounds.getCenterY() + (float) translate.y * scale, 0); + matrix.multiply(Matrix4f.createScaleMatrix(scale, scale, 1)); + return matrix; + } + + @Override + 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.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()) + )); + if (!RoughlyEnoughItemsCoreClient.isLeftMousePressed) { + this.translate.setAs(new FloatingPoint(this.translate.value().x + this.velocity.value().x, this.translate.value().y + this.velocity.value().y)); + } + this.velocity.update(delta); + this.velocity.setTo(new FloatingPoint( + ScrollingContainer.handleBounceBack(this.velocity.target().x, 0, delta, .0001), + ScrollingContainer.handleBounceBack(this.velocity.target().y, 0, delta, .0001) + ), 20); + + ScissorsHandler.INSTANCE.scissor(this.bounds); + super.render(poseStack, mouseX, mouseY, delta); + ScissorsHandler.INSTANCE.removeLastScissor(); + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public boolean containsMouse(double mouseX, double mouseY) { + return getBounds().contains(mouseX, mouseY); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (containsMouse(mouseX, mouseY)) { + this.scale.setTo(this.scale.target() + amount * -0.2f, 300); + return true; + } + + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) return true; + if (containsMouse(mouseX, mouseY) && button == 0) { + dragging = true; + return true; + } + + return false; + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + if (dragging && button == 0) { + dragging = false; + return true; + } + + return super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (dragging && button == 0) { + double newXTranslate = translate.target().x; + double newYTranslate = translate.target().y; + newXTranslate += deltaX * scale.doubleValue(); + newYTranslate += deltaY * scale.doubleValue(); + + translate.setAs(new FloatingPoint(newXTranslate, newYTranslate)); + velocity.setAs(new FloatingPoint(deltaX * scale.doubleValue(), deltaY * scale.doubleValue())); + return true; + } + + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } +} -- cgit