From c027169dfe9503a9d913589eb322cc11ddad0baa Mon Sep 17 00:00:00 2001 From: shedaniel Date: Tue, 23 Mar 2021 00:02:16 +0800 Subject: Improve UncertainDisplayViewingScreen Signed-off-by: shedaniel --- .../rei/gui/UncertainDisplayViewingScreen.java | 294 +++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 runtime/src/main/java/me/shedaniel/rei/gui/UncertainDisplayViewingScreen.java (limited to 'runtime/src/main/java/me/shedaniel/rei/gui/UncertainDisplayViewingScreen.java') diff --git a/runtime/src/main/java/me/shedaniel/rei/gui/UncertainDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/gui/UncertainDisplayViewingScreen.java new file mode 100644 index 000000000..d2664bb4f --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/gui/UncertainDisplayViewingScreen.java @@ -0,0 +1,294 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 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.gui; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.architectury.platform.Platform; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget; +import me.shedaniel.clothconfig2.impl.EasingMethod; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.ClientHelper; +import me.shedaniel.rei.api.REIHelper; +import me.shedaniel.rei.api.gui.config.DisplayScreenType; +import me.shedaniel.rei.api.gui.widgets.Button; +import me.shedaniel.rei.api.gui.widgets.Widget; +import me.shedaniel.rei.api.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.gui.widgets.Widgets; +import me.shedaniel.rei.api.util.ImmutableLiteralText; +import me.shedaniel.rei.impl.Animator; +import me.shedaniel.rei.impl.Internals; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.gui.components.AbstractSliderButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@ApiStatus.Internal +public class UncertainDisplayViewingScreen extends Screen { + private static final ResourceLocation DEFAULT = new ResourceLocation("roughlyenoughitems", "textures/gui/screenshot_default.png"); + private static final ResourceLocation COMPOSITE = new ResourceLocation("roughlyenoughitems", "textures/gui/screenshot_composite.png"); + private final List widgets; + protected long start; + protected long duration; + private boolean isSet; + private boolean original; + private double frame = 0; + private double target = 0; + private BooleanConsumer callback; + private Button button; + private Screen parent; + private Widget slider; + private boolean showTips; + private Animator scroll = new Animator(); + private List allModsUsingJEI = new ArrayList<>(); + + public UncertainDisplayViewingScreen(Screen parent, DisplayScreenType type, boolean showTips, BooleanConsumer callback) { + super(ImmutableLiteralText.EMPTY); + this.widgets = Lists.newArrayList(); + if (type == DisplayScreenType.UNSET) { + this.isSet = false; + this.original = true; + } else { + this.isSet = true; + this.original = type == DisplayScreenType.ORIGINAL; + moveFrameTo(original ? 0 : 1, false, 0); + } + this.scroll.setAs(0); + this.callback = callback; + this.parent = parent; + this.showTips = showTips; + if (showTips && Platform.isForge()) { + allModsUsingJEI = Internals.getJeiCompatMods().stream() + .distinct() + .map(ClientHelper.getInstance()::getModFromModId) + .collect(Collectors.toList()); + } + } + + public final double clamp(double v) { + return clamp(v, 30); + } + + public final double clamp(double v, double clampExtension) { + return Mth.clamp(v, -clampExtension, 1 + clampExtension); + } + + private void moveFrameTo(double value, boolean animated, long duration) { + target = clamp(value); + + if (animated) { + start = System.currentTimeMillis(); + this.duration = duration; + } else { + frame = target; + } + } + + @Override + public void init() { + this.children.clear(); + this.widgets.clear(); + this.children.add(button = Widgets.createButton(new Rectangle(width / 2 - 100, height - 40, 200, 20), NarratorChatListener.NO_TITLE) + .onRender((matrices, button) -> { + button.setEnabled(isSet); + if (scroll.target() != 0 && allModsUsingJEI != null) { + button.setText(new TranslatableComponent("gui.done")); + } else { + button.setText(isSet ? new TranslatableComponent("text.rei.select") : new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.unset")); + } + }) + .onClick(button -> { + if (scroll.target() == 0 && allModsUsingJEI != null) { + scroll.setTo(200, 450); + } else { + callback.accept(original); + } + })); + this.widgets.add(transformScroll(new ScreenTypeSelection(width / 2 - 200 - 5, height / 2 - 112 / 2 - 10, DisplayScreenType.ORIGINAL))); + this.widgets.add(transformScroll(Widgets.createLabel(new Point(width / 2 - 200 - 5 + 104, height / 2 - 112 / 2 + 115), new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.original")).noShadow().color(-1124073473))); + this.widgets.add(transformScroll(new ScreenTypeSelection(width / 2 + 5, height / 2 - 112 / 2 - 10, DisplayScreenType.COMPOSITE))); + this.widgets.add(transformScroll(Widgets.createLabel(new Point(width / 2 + 5 + 104, height / 2 - 112 / 2 + 115), new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.composite")).noShadow().color(-1124073473))); + this.widgets.add(slider = transformScroll(Widgets.wrapVanillaWidget(new AbstractSliderButton(width / 2 - 100, height * 2 - 64, 200, 20, new TranslatableComponent("text.rei.jei_compat.false"), 0) { + @Override + protected void updateMessage() { + setMessage(new TranslatableComponent("text.rei.jei_compat." + (value == 1f))); + } + + @Override + protected void applyValue() { + + } + + @Override + public void renderButton(PoseStack poseStack, int i, int j, float f) { + y = UncertainDisplayViewingScreen.this.height * 2 - 64; + super.renderButton(poseStack, i, j, f); + y = UncertainDisplayViewingScreen.this.height * 2 - 64 - (int) (scroll.floatValue() / 200f * height); + } + }))); + this.children.addAll(widgets); + } + + private Widget transformScroll(Widget widget) { + return Widgets.withTranslate(widget, () -> Matrix4f.createTranslateMatrix(0, -(scroll.floatValue() / 200f * height), 0)); + } + + @Override + public void render(PoseStack matrices, int int_1, int int_2, float float_1) { + scroll.update(float_1); + if (this.minecraft.level != null) { + this.fillGradient(matrices, 0, 0, this.width, this.height, -1072689136, -804253680); + } else { + this.fillGradient(matrices, 0, 0, this.width, this.height, -16777216, -16777216); + } + if (scroll.target() == 0) { + drawCenteredString(matrices, this.font, new TranslatableComponent("text.rei.recipe_screen_type.selection"), this.width / 2, 20, 16777215); + } else { + drawCenteredString(matrices, this.font, new TranslatableComponent("text.rei.jei_compat"), this.width / 2, 20, 16777215); + } + ScissorsHandler.INSTANCE.scissor(new Rectangle(0, 20 + font.lineHeight + 2, width, height - 42)); + if (showTips) { + float i = 32 - (scroll.floatValue() / 200f * height); + for (FormattedCharSequence s : this.font.split(new TranslatableComponent("text.rei.recipe_screen_type.selection.sub").withStyle(ChatFormatting.GRAY), width - 30)) { + font.drawShadow(matrices, s, width / 2 - font.width(s) / 2, i, -1); + i += 10; + } + if (allModsUsingJEI != null) { + i = 32 + height - (scroll.floatValue() / 200f * height); + for (FormattedCharSequence s : this.font.split(new TranslatableComponent("text.rei.jei_compat.sub", new TranslatableComponent("text.rei.jei_compat.sub.stability"), + new TextComponent(String.join(", ", allModsUsingJEI))).withStyle(ChatFormatting.GRAY), width - 30)) { + font.drawShadow(matrices, s, width / 2 - font.width(s) / 2, i, -1); + i += 10; + } + } + } + super.render(matrices, int_1, int_2, float_1); + for (Widget widget : widgets) { + widget.render(matrices, int_1, int_2, float_1); + } + if (isSet) { + matrices.pushPose(); + matrices.translate(0, -(scroll.floatValue() / 200f * height), 0); + updateFramePosition(float_1); + int x = (int) (width / 2 - 205 + (210 * frame)); + int y = height / 2 - 112 / 2 - 10; + fillGradient(matrices, x - 2, y - 4, x - 6 + 208, y - 4 + 2, -1778384897, -1778384897); + fillGradient(matrices, x - 2, y - 4 + 126 - 2, x - 6 + 208, y - 4 + 126, -1778384897, -1778384897); + fillGradient(matrices, x - 4, y - 4, x - 4 + 2, y - 4 + 126, -1778384897, -1778384897); + fillGradient(matrices, x - 4 + 208 - 2, y - 4, x - 4 + 208, y - 4 + 126, -1778384897, -1778384897); + matrices.popPose(); + } + ScissorsHandler.INSTANCE.removeLastScissor(); + button.render(matrices, int_1, int_2, float_1); + } + + private void updateFramePosition(float delta) { + target = clamp(target); + if (!DynamicNewSmoothScrollingEntryListWidget.Precision.almostEquals(frame, target, DynamicNewSmoothScrollingEntryListWidget.Precision.FLOAT_EPSILON)) + frame = ease(frame, target, Math.min((System.currentTimeMillis() - start) / (double) duration * delta * 3.0D, 1)); + else + frame = target; + } + + private double ease(double start, double end, double amount) { + return start + (end - start) * EasingMethod.EasingMethodImpl.LINEAR.apply(amount); + } + + @Override + public boolean keyPressed(int int_1, int int_2, int int_3) { + if (int_1 == 256 || this.minecraft.options.keyInventory.matches(int_1, int_2)) { + Minecraft.getInstance().setScreen(parent); + if (parent instanceof AbstractContainerScreen) { + REIHelper.getInstance().getOverlay().get().queueReloadOverlay(); + } + return true; + } + return super.keyPressed(int_1, int_2, int_3); + } + + @Override + public boolean mouseDragged(double d, double e, int i, double f, double g) { + return slider.mouseDragged(d, e, i, f, g) || super.mouseDragged(d, e, i, f, g); + } + + public class ScreenTypeSelection extends WidgetWithBounds { + private final DisplayScreenType type; + private Rectangle bounds; + + public ScreenTypeSelection(int x, int y, DisplayScreenType type) { + this.type = type; + this.bounds = new Rectangle(x - 4 + 16, y - 4, 176 + 8, 120 + 8); + } + + @NotNull + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack matrices, int i, int i1, float delta) { + Minecraft.getInstance().getTextureManager().bind(type == DisplayScreenType.ORIGINAL ? DEFAULT : COMPOSITE); + blit(matrices, bounds.x + (type == DisplayScreenType.ORIGINAL ? 8 : 4), bounds.y + 4, bounds.width - 8, bounds.height - 8, 113, type == DisplayScreenType.ORIGINAL ? 16 : 27, 854 - 113 * 2, 480 - 27 * 2, 854, 480); + } + + @Override + public boolean mouseClicked(double double_1, double double_2, int int_1) { + if (containsMouse(double_1, double_2)) { + original = (type == DisplayScreenType.ORIGINAL); + if (!isSet) { + moveFrameTo(original ? 0 : 1, false, 0); + } + isSet = true; + moveFrameTo(original ? 0 : 1, true, 500); + return true; + } + return false; + } + + @Override + public List children() { + return Collections.emptyList(); + } + } +} -- cgit