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 00000000..d094242f Binary files /dev/null and b/src/main/resources/assets/bclib/icon_bright.png differ