From 799018222cdb2656ec67722c9a94b4f3f442dcbf Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 23 Jul 2022 00:58:51 +0200 Subject: [PATCH] Improved WorldSetupScreen --- .../client/gui/screens/BCLibLayoutScreen.java | 1 + .../client/gui/screens/WorldSetupScreen.java | 135 +++++++++++++++++- .../components/AbstractHorizontalStack.java | 2 +- .../ui/layout/components/AbstractStack.java | 9 ++ .../ui/layout/components/Container.java | 8 ++ .../ui/layout/components/LayoutComponent.java | 14 +- .../ui/layout/components/MultiLineText.java | 4 +- .../betterx/ui/layout/components/Panel.java | 1 + .../betterx/ui/layout/components/Tabs.java | 28 +++- .../ui/layout/components/VerticalScroll.java | 6 + .../components/render/ButtonRenderer.java | 68 ++++++++- .../resources/assets/bclib/icon_bright.png | Bin 0 -> 16830 bytes 12 files changed, 264 insertions(+), 12 deletions(-) create mode 100644 src/main/resources/assets/bclib/icon_bright.png diff --git a/src/main/java/org/betterx/bclib/client/gui/screens/BCLibLayoutScreen.java b/src/main/java/org/betterx/bclib/client/gui/screens/BCLibLayoutScreen.java index 711c0acb..ecf28cf9 100644 --- a/src/main/java/org/betterx/bclib/client/gui/screens/BCLibLayoutScreen.java +++ b/src/main/java/org/betterx/bclib/client/gui/screens/BCLibLayoutScreen.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; public abstract class BCLibLayoutScreen extends LayoutScreenWithIcon { static final ResourceLocation BCLIB_LOGO_LOCATION = new ResourceLocation(BCLib.MOD_ID, "icon.png"); + static final ResourceLocation BCLIB_LOGO_WHITE_LOCATION = new ResourceLocation(BCLib.MOD_ID, "icon_bright.png"); public BCLibLayoutScreen( Component component diff --git a/src/main/java/org/betterx/bclib/client/gui/screens/WorldSetupScreen.java b/src/main/java/org/betterx/bclib/client/gui/screens/WorldSetupScreen.java index b130328f..4d928435 100644 --- a/src/main/java/org/betterx/bclib/client/gui/screens/WorldSetupScreen.java +++ b/src/main/java/org/betterx/bclib/client/gui/screens/WorldSetupScreen.java @@ -7,11 +7,15 @@ import org.betterx.bclib.api.v2.generator.config.BCLNetherBiomeSourceConfig; import org.betterx.bclib.api.v2.levelgen.LevelGenUtil; import org.betterx.bclib.registry.PresetsRegistry; import org.betterx.ui.layout.components.*; +import org.betterx.ui.layout.components.render.RenderHelper; +import org.betterx.ui.layout.values.Rectangle; import org.betterx.ui.layout.values.Size; import org.betterx.ui.vanilla.LayoutScreen; import org.betterx.worlds.together.worldPreset.TogetherWorldPreset; import org.betterx.worlds.together.worldPreset.WorldGenSettingsComponentAccessor; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen; import net.minecraft.client.gui.screens.worldselection.WorldCreationContext; import net.minecraft.core.Holder; @@ -292,6 +296,10 @@ public class WorldSetupScreen extends LayoutScreen { return cols; } + Button netherButton, endButton; + VerticalScroll scroller; + HorizontalStack title; + @Override protected LayoutComponent initContent() { BCLEndBiomeSourceConfig endConfig = BCLEndBiomeSourceConfig.VANILLA; @@ -317,12 +325,19 @@ public class WorldSetupScreen extends LayoutScreen { Tabs main = new Tabs(fill(), fill()).setPadding(8, 0, 0, 0); main.addPage(Component.translatable("title.bclib.the_nether"), VerticalScroll.create(netherPage)); - main.addPage(Component.translatable("title.bclib.the_end"), VerticalScroll.create(endPage)); + main.addSpacer(8); + main.addPage(Component.translatable("title.bclib.the_end"), scroller = VerticalScroll.create(endPage)); + netherButton = main.getButton(0); + endButton = main.getButton(1); - HorizontalStack title = new HorizontalStack(fit(), fit()).setDebugName("title bar"); - title.addIcon(BCLibLayoutScreen.BCLIB_LOGO_LOCATION, Size.of(512)).setDebugName("icon"); + title = new HorizontalStack(fit(), fit()).setDebugName("title bar").alignBottom(); + title.addImage(fixed(22), fixed(22), BCLibLayoutScreen.BCLIB_LOGO_WHITE_LOCATION, Size.of(256)) + .setDebugName("icon"); title.addSpacer(4); - title.add(super.buildTitle()); + VerticalStack logos = title.addColumn(fit(), fit()); + logos.addImage(fixed(178 / 3), fixed(40 / 3), WelcomeScreen.BETTERX_LOCATION, Size.of(178, 40)); + logos.add(super.buildTitle()); + logos.addSpacer(2); main.addFiller(); main.addComponent(title); @@ -336,6 +351,118 @@ public class WorldSetupScreen extends LayoutScreen { onClose(); }).alignRight(); + main.onPageChange((tabs, idx) -> { + targetT = 1 - idx; + }); + return rows; } + + @Override + protected void renderBackground(PoseStack poseStack, int i, int j, float f) { + GuiComponent.fill(poseStack, 0, 0, width, height, 0xBD343444); + } + + record IconState(int left, int top, int size) { + //easing curves from https://easings.net/de + static double easeInOutQuint(double t) { + return t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2; + } + + static double easeOutBounce(double x) { + final double n1 = 7.5625; + final double d1 = 2.75; + + if (x < 1 / d1) { + return n1 * x * x; + } else if (x < 2 / d1) { + return n1 * (x -= 1.5 / d1) * x + 0.75; + } else if (x < 2.5 / d1) { + return n1 * (x -= 2.25 / d1) * x + 0.9375; + } else { + return n1 * (x -= 2.625 / d1) * x + 0.984375; + } + } + + static int lerp(double t, int x0, int x1) { + return (int) ((1 - t) * x0 + t * x1); + } + } + + IconState netherOff, netherOn, endOff, endOn; + double iconT = 0.5; + double targetT = 1; + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + super.render(poseStack, i, j, f); + final double SPEED = 0.05; + if (targetT < iconT && iconT > 0) iconT = Math.max(0, iconT - f * SPEED); + else if (targetT > iconT && iconT < 1) iconT = Math.min(1, iconT + f * SPEED); + + final double t; + if (iconT > 0 && iconT < 1) { + if (targetT > iconT) { + t = IconState.easeOutBounce(iconT); + } else { + t = 1 - IconState.easeOutBounce(1 - iconT); + } + } else t = iconT; + + if (endButton != null) { + if (endOff == null) { + endOff = new IconState( + endButton.getScreenBounds().right() - 12, + endButton.getScreenBounds().top - 7, + 16 + ); + endOn = new IconState( + (title.getScreenBounds().left - endButton.getScreenBounds().right()) / 2 + + endButton.getScreenBounds().right() + - 14, + scroller.getScreenBounds().top - 16, + 32 + ); + } + poseStack.pushPose(); + poseStack.translate( + IconState.lerp(t, endOn.left, endOff.left), + IconState.lerp(t, endOn.top, endOff.top), + 0 + ); + int size = IconState.lerp(t, endOn.size, endOff.size); + RenderHelper.renderImage( + poseStack, size, size, + WelcomeScreen.ICON_BETTEREND, + new Rectangle(0, 0, 32, 32), + Size.of(32), 1 + ); + poseStack.popPose(); + } + + if (netherButton != null) { + if (netherOff == null) { + netherOff = new IconState( + netherButton.getScreenBounds().right() - 12, + netherButton.getScreenBounds().top - 7, + 16 + ); + netherOn = endOn; + } + poseStack.pushPose(); + poseStack.translate( + IconState.lerp(t, netherOff.left, netherOn.left), + IconState.lerp(t, netherOff.top, netherOn.top), + 0 + ); + int size = IconState.lerp(t, netherOff.size, netherOn.size); + RenderHelper.renderImage( + poseStack, size, size, + WelcomeScreen.ICON_BETTERNETHER, + new Rectangle(0, 0, 32, 32), + Size.of(32), 1 + ); + poseStack.popPose(); + } + } } diff --git a/src/main/java/org/betterx/ui/layout/components/AbstractHorizontalStack.java b/src/main/java/org/betterx/ui/layout/components/AbstractHorizontalStack.java index b34cf98a..a7a4debf 100644 --- a/src/main/java/org/betterx/ui/layout/components/AbstractHorizontalStack.java +++ b/src/main/java/org/betterx/ui/layout/components/AbstractHorizontalStack.java @@ -39,7 +39,7 @@ public class AbstractHorizontalStack> exten return myHeight; } - + @Override void setRelativeBounds(int left, int top) { super.setRelativeBounds(left, top); diff --git a/src/main/java/org/betterx/ui/layout/components/AbstractStack.java b/src/main/java/org/betterx/ui/layout/components/AbstractStack.java index 81f26dec..f17ed786 100644 --- a/src/main/java/org/betterx/ui/layout/components/AbstractStack.java +++ b/src/main/java/org/betterx/ui/layout/components/AbstractStack.java @@ -47,6 +47,15 @@ public abstract class AbstractStack c : components) { + c.updateScreenBounds(screenBounds.left, screenBounds.top); + } + } + + @Override protected void renderInBounds( PoseStack poseStack, diff --git a/src/main/java/org/betterx/ui/layout/components/Container.java b/src/main/java/org/betterx/ui/layout/components/Container.java index 293d887d..809afe6b 100644 --- a/src/main/java/org/betterx/ui/layout/components/Container.java +++ b/src/main/java/org/betterx/ui/layout/components/Container.java @@ -209,6 +209,14 @@ public class Container extends LayoutComponent c : children) { + c.updateScreenBounds(screenBounds.left, screenBounds.top); + } + } + @Override public void mouseMoved(double d, double e) { if (visible) diff --git a/src/main/java/org/betterx/ui/layout/components/LayoutComponent.java b/src/main/java/org/betterx/ui/layout/components/LayoutComponent.java index fe655205..48e68ada 100644 --- a/src/main/java/org/betterx/ui/layout/components/LayoutComponent.java +++ b/src/main/java/org/betterx/ui/layout/components/LayoutComponent.java @@ -20,6 +20,7 @@ public abstract class LayoutComponent { + @FunctionalInterface + public interface OnPageChange { + void now(Tabs tabs, int pageIndex); + } + private final HorizontalStack buttons; private final Container content; @@ -20,6 +25,8 @@ public class Tabs extends AbstractVerticalStack { private int initialPage = 0; + private OnPageChange onPageChange; + public Tabs(Value width, Value height) { super(width, height); @@ -45,9 +52,16 @@ public class Tabs extends AbstractVerticalStack { for (Container cc : pageList) { cc.setVisible(cc == c); } + for (Button bb : buttonList) { bb.glow = bb == b; } + + if (onPageChange != null) { + for (int i = 0; i < buttonList.size(); i++) { + if (buttonList.get(i).glow) onPageChange.now(this, i); + } + } }); buttons.add(b); buttonList.add(b); @@ -56,6 +70,15 @@ public class Tabs extends AbstractVerticalStack { return this; } + public Tabs onPageChange(OnPageChange e) { + this.onPageChange = e; + return this; + } + + public Button getButton(int idx) { + return buttonList.get(idx); + } + public Tabs setBackgroundColor(int color) { content.setBackgroundColor(color); return this; @@ -108,9 +131,10 @@ public class Tabs extends AbstractVerticalStack { return this; } + @Override - void setRelativeBounds(int left, int top) { - super.setRelativeBounds(left, top); + protected void onBoundsChanged() { + super.onBoundsChanged(); selectPage(initialPage); } diff --git a/src/main/java/org/betterx/ui/layout/components/VerticalScroll.java b/src/main/java/org/betterx/ui/layout/components/VerticalScroll.java index 9df4ffe8..f8b8a6df 100644 --- a/src/main/java/org/betterx/ui/layout/components/VerticalScroll.java +++ b/src/main/java/org/betterx/ui/layout/components/VerticalScroll.java @@ -132,6 +132,12 @@ public class VerticalScroll extends LayoutComponent updateScrollViewMetrics(); } + @Override + public void updateScreenBounds(int worldX, int worldY) { + super.updateScreenBounds(worldX, worldY); + child.updateScreenBounds(screenBounds.left, screenBounds.top); + } + @Override protected void renderInBounds( PoseStack poseStack, diff --git a/src/main/java/org/betterx/ui/layout/components/render/ButtonRenderer.java b/src/main/java/org/betterx/ui/layout/components/render/ButtonRenderer.java index 85b3ed69..5839f151 100644 --- a/src/main/java/org/betterx/ui/layout/components/render/ButtonRenderer.java +++ b/src/main/java/org/betterx/ui/layout/components/render/ButtonRenderer.java @@ -6,12 +6,16 @@ import org.betterx.ui.layout.components.Button; import org.betterx.ui.layout.values.Rectangle; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.GuiComponent; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @Environment(EnvType.CLIENT) public class ButtonRenderer extends AbstractVanillaComponentRenderer { + double deltaSum = 0; + double deltaSum2 = .34; + double deltaSum3 = .12; @Override public void renderInBounds( @@ -23,8 +27,70 @@ public class ButtonRenderer extends AbstractVanillaComponentRenderer w && pos<=w+h : x=w, y=pos-w + * pos >w+h && pos<=2w+h : x=2w +h - pos, y=h + * pos>2w+h : x=0, y=2w+2h-pos + */ + if (pos <= bounds.width) { + x = pos; + y = 0; + } else if (pos <= bh) { + x = bounds.width - 1; + y = pos - bounds.width; + } else if (pos <= bh + bounds.width) { + x = bh + bounds.width - pos; + y = bounds.height - 1; + } else { + x = 0; + y = 2 * bh - pos; + } + GuiComponent.fill(poseStack, x, y, x + 1, y + 1, ColorUtil.BLACK); + } } diff --git a/src/main/resources/assets/bclib/icon_bright.png b/src/main/resources/assets/bclib/icon_bright.png new file mode 100644 index 0000000000000000000000000000000000000000..d094242f9812531b8c667bf6a03c9736dd4328e7 GIT binary patch literal 16830 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 Yy<5at