From 457a8d10d3eec3625a3683be5f09abaf287f5290 Mon Sep 17 00:00:00 2001 From: Oth3r Date: Fri, 30 Aug 2024 20:29:03 -0500 Subject: [PATCH] new ModMenu UI --- .../sit/screen/ClickableImageWidget.java | 32 +++ .../one/oth3r/sit/screen/ConfigScreen.java | 79 ++++++++ .../java/one/oth3r/sit/screen/ModMenu.java | 184 +----------------- .../oth3r/sit/screen/TextureButtonWidget.java | 85 ++++++++ .../sit/screen/UnderConstructionScreen.java | 70 +++++++ 5 files changed, 271 insertions(+), 179 deletions(-) create mode 100644 src/main/java/one/oth3r/sit/screen/ClickableImageWidget.java create mode 100644 src/main/java/one/oth3r/sit/screen/ConfigScreen.java create mode 100644 src/main/java/one/oth3r/sit/screen/TextureButtonWidget.java create mode 100644 src/main/java/one/oth3r/sit/screen/UnderConstructionScreen.java diff --git a/src/main/java/one/oth3r/sit/screen/ClickableImageWidget.java b/src/main/java/one/oth3r/sit/screen/ClickableImageWidget.java new file mode 100644 index 0000000..2368fba --- /dev/null +++ b/src/main/java/one/oth3r/sit/screen/ClickableImageWidget.java @@ -0,0 +1,32 @@ +package one.oth3r.sit.screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.function.Supplier; + +public class ClickableImageWidget extends ButtonWidget { + private final Identifier image; + + public ClickableImageWidget(int x, int y, int width, int height, Tooltip tooltip, Identifier image, ButtonWidget.PressAction onPress) { + super(x, y, width, height, Text.empty(), onPress, Supplier::get); + this.image = image; + this.setTooltip(tooltip); + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + context.setShaderColor(1.0f, 1.0f, 1.0f, this.alpha); + RenderSystem.enableBlend(); + RenderSystem.enableDepthTest(); + context.drawTexture(image, this.getX(), this.getY(), 0.0f, 0.0f, this.getWidth(), this.getHeight(), this.getWidth(), this.getHeight()); + context.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + + +} diff --git a/src/main/java/one/oth3r/sit/screen/ConfigScreen.java b/src/main/java/one/oth3r/sit/screen/ConfigScreen.java new file mode 100644 index 0000000..d67e1f7 --- /dev/null +++ b/src/main/java/one/oth3r/sit/screen/ConfigScreen.java @@ -0,0 +1,79 @@ +package one.oth3r.sit.screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ConfirmLinkScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import one.oth3r.sit.file.FileData; +import one.oth3r.sit.utl.Data; + +import java.net.URI; + +public class ConfigScreen extends Screen { + protected final Screen parent; + + public ConfigScreen(Screen parent) { + super(Text.translatable("screen.config")); + this.parent = parent; + } + + @Override + protected void init() { + int startY = this.height / 4 + 48; + int spacing = 36; + TextureButtonWidget serverConfigButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("config.server"), + (button) -> client.setScreen(new UnderConstructionScreen(this, FileData.getServerConfig())), false) + .dimensions(250,30).texture(Identifier.of(Data.MOD_ID, "server_button"), 246, 26).build()); + serverConfigButton.setPosition(this.width / 2 - (serverConfigButton.getWidth()/2), startY); + + TextureButtonWidget sittingConfigButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("config.sitting"), + (button) -> client.setScreen(new UnderConstructionScreen(this, FileData.getSittingConfig())), false) + .dimensions(250,30).texture(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26).build()); + sittingConfigButton.setPosition(this.width / 2 - (sittingConfigButton.getWidth()/2), startY+36); + + + TextureButtonWidget issuesButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("gui.button.issues"), + ConfirmLinkScreen.opening(this, URI.create("https://github.com/Oth3r/Sit/issues")), true) + .dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "issues"), 15, 15).build()); + issuesButton.setPosition(this.width / 2 - 125, startY + 72 + 12); + + + this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.button.website"), + ConfirmLinkScreen.opening(this, URI.create("https://modrinth.com/mod/sit!")) + ).dimensions(this.width / 2 - 100, startY + 72 + 12, 98, 20).build()); + + this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.done"), (button) -> { + close(); + }).dimensions(this.width / 2 + 2, startY + 72 + 12, 98, 20).build()); + + TextureButtonWidget donateButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("gui.button.donate"), + ConfirmLinkScreen.opening(this, URI.create("https://Ko-fi.com/oth3r")), true) + .dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "donate"), 15, 15).build()); + donateButton.setPosition(this.width / 2 + 105, startY + 72 + 12); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + //todo fade? + renderBanner(context,width/2 - 64,this.height / 4 -38,1); + } + + @Override + public void close() { + this.client.setScreen(parent); + } + + private void renderBanner(DrawContext context, int x, int y, float alpha) { + context.setShaderColor(1.0f, 1.0f, 1.0f, alpha); + RenderSystem.enableBlend(); + + context.drawTexture(Identifier.of(Data.MOD_ID, "textures/gui/banner.png"), x, y, 0.0f, 0.0f, 128, 72, 128, 72); + + context.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + RenderSystem.disableBlend(); + } +} diff --git a/src/main/java/one/oth3r/sit/screen/ModMenu.java b/src/main/java/one/oth3r/sit/screen/ModMenu.java index 264f20b..7a64bf2 100644 --- a/src/main/java/one/oth3r/sit/screen/ModMenu.java +++ b/src/main/java/one/oth3r/sit/screen/ModMenu.java @@ -1,185 +1,11 @@ package one.oth3r.sit.screen; +import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; public class ModMenu implements ModMenuApi { -// private static MutableText lang(String key, Object... args) { -// return Utl.lang("config."+key,args); -// } -// @Override -// public ConfigScreenFactory getModConfigScreenFactory() { -// return parent -> YetAnotherConfigLib.createBuilder().save(config::save) -// .title(Text.of("Sit!")) -// .category(ConfigCategory.createBuilder() -// .name(lang("category.general")) -// .option(Option.createBuilder() -// .name(lang("general.keep_active")) -// .description(OptionDescription.of(lang("general.keep_active.description"))) -// .binding(config.defaults.keepActive, () -> config.keepActive, n -> config.keepActive = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("general.sit_while_seated")) -// .description(OptionDescription.of(lang("general.sit_while_seated.description"))) -// .binding(config.defaults.sitWhileSeated, () -> config.sitWhileSeated, n -> config.sitWhileSeated = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .group(OptionGroup.createBuilder() -// .name(lang("general.sittable")) -// .description(OptionDescription.of(lang("general.sittable.description"))) -// .option(Option.createBuilder() -// .name(lang("general.sittable.stairs")) -// .binding(config.defaults.stairsOn, () -> config.stairsOn, n -> config.stairsOn = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("general.sittable.slabs")) -// .binding(config.defaults.slabsOn, () -> config.slabsOn, n -> config.slabsOn = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("general.sittable.carpets")) -// .binding(config.defaults.carpetsOn, () -> config.carpetsOn, n -> config.carpetsOn = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("general.sittable.full_blocks")) -// .binding(config.defaults.fullBlocksOn, () -> config.fullBlocksOn, n -> config.fullBlocksOn = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("general.sittable.custom")) -// .description(OptionDescription.of(lang("general.sittable.custom.description"))) -// .binding(config.defaults.customOn, () -> config.customOn, n -> config.customOn = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) -// .build()) -// .build()) -// .group(ListOption.createBuilder() -// .name(lang("general.sittable_blocks")) -// .description(OptionDescription.of( -// lang("general.sittable_blocks.description") -// .append("\n\n").append(lang("example", -// Text.literal("\"") -// .append(Text.literal("minecraft:campfire").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) -// .append("|") -// .append(Text.literal("0.255").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))) -// .append("|") -// .append(Text.literal("1").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) -// .append("|") -// .append(Text.literal("lit=false").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD)))) -// .append("\"").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GRAY))))) -// .append("\n\n").append(lang("general.sittable_blocks.description.2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) -// .append("\n").append(lang("general.sittable_blocks.description.3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))) -// .append("\n").append(lang("general.sittable_blocks.description.4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) -// .append("\n").append(lang("general.sittable_blocks.description.5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD)))) -// .append("\n\n").append(lang("general.sittable_blocks.description.6").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.YELLOW)))))) -// .binding(config.defaults.customBlocks, () -> config.customBlocks, n -> config.customBlocks = n) -// .controller(StringControllerBuilder::create) -// .initial("") -// .build()) -// .build()) -// .category(ConfigCategory.createBuilder() -// .name(lang("category.main_hand")) -// .option(Option.createBuilder() -// .name(lang("hand.requirement")) -// .description(OptionDescription.of(lang("hand.requirement.description") -// .append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) -// .append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) -// .append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))))) -// .binding(config.defaults.mainReq, () -> config.mainReq, n -> config.mainReq = n) -// .controller(opt -> EnumControllerBuilder.create(opt).enumClass(config.HandRequirement.class) -// .formatValue(v -> lang("hand.requirement."+v.toString()))) -// .build()) -// .group(OptionGroup.createBuilder() -// .name(lang("hand.restriction")) -// .description(OptionDescription.of(lang("hand.restriction.description"))) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.blocks")) -// .binding(config.defaults.mainBlock,()-> config.mainBlock,n -> config.mainBlock = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.food")) -// .binding(config.defaults.mainFood,()-> config.mainFood,n -> config.mainFood = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.usable")) -// .description(OptionDescription.of(lang("hand.restriction.usable.description"))) -// .binding(config.defaults.mainUsable,()-> config.mainUsable,n -> config.mainUsable = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .build()) -// .group(ListOption.createBuilder() -// .name(lang("hand.restriction.whitelist")) -// .description(OptionDescription.of(lang("hand.restriction.list.description") -// .append("\n\n").append(lang("example", -// Text.empty().append(Utl.Assets.LIST).styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))) -// .binding(config.defaults.mainWhitelist, () -> config.mainWhitelist, n -> config.mainWhitelist = n) -// .controller(StringControllerBuilder::create) -// .initial("") -// .build()) -// .group(ListOption.createBuilder() -// .name(lang("hand.restriction.blacklist")) -// .description(OptionDescription.of(lang("hand.restriction.list.description") -// .append("\n\n").append(lang("example", -// Text.empty().append(Utl.Assets.LIST).styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))) -// .binding(config.defaults.mainBlacklist, () -> config.mainBlacklist, n -> config.mainBlacklist = n) -// .controller(StringControllerBuilder::create) -// .initial("") -// .build()) -// .build()) -// .category(ConfigCategory.createBuilder() -// .name(lang("category.off_hand")) -// .option(Option.createBuilder() -// .name(lang("hand.requirement")) -// .description(OptionDescription.of(lang("hand.requirement.description") -// .append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) -// .append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) -// .append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))))) -// .binding(config.defaults.offReq, () -> config.offReq, n -> config.offReq = n) -// .controller(opt -> EnumControllerBuilder.create(opt).enumClass(config.HandRequirement.class) -// .formatValue(v -> lang("hand.requirement."+v.toString()))) -// .build()) -// .group(OptionGroup.createBuilder() -// .name(lang("hand.restriction")) -// .description(OptionDescription.of(lang("hand.restriction.description"))) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.blocks")) -// .binding(config.defaults.offBlock,()-> config.offBlock,n -> config.offBlock = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.food")) -// .binding(config.defaults.offFood,()-> config.offFood,n -> config.offFood = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .option(Option.createBuilder() -// .name(lang("hand.restriction.usable")) -// .description(OptionDescription.of(lang("hand.restriction.usable.description"))) -// .binding(config.defaults.offUsable,()-> config.offUsable,n -> config.offUsable = n) -// .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) -// .build()) -// .build()) -// .group(ListOption.createBuilder() -// .name(lang("hand.restriction.whitelist")) -// .description(OptionDescription.of(lang("hand.restriction.list.description") -// .append("\n\n").append(lang("example", -// Text.empty().append(Utl.Assets.LIST).styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))) -// .binding(config.defaults.offWhitelist, () -> config.offWhitelist, n -> config.offWhitelist = n) -// .controller(StringControllerBuilder::create) -// .initial("") -// .build()) -// .group(ListOption.createBuilder() -// .name(lang("hand.restriction.blacklist")) -// .description(OptionDescription.of(lang("hand.restriction.list.description") -// .append("\n\n").append(lang("example", -// Text.empty().append(Utl.Assets.LIST).styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))) -// .binding(config.defaults.offBlacklist, () -> config.offBlacklist, n -> config.offBlacklist = n) -// .controller(StringControllerBuilder::create) -// .initial("") -// .build()) -// .build()) -// .build().generateScreen(parent); -// } + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return ConfigScreen::new; + } } diff --git a/src/main/java/one/oth3r/sit/screen/TextureButtonWidget.java b/src/main/java/one/oth3r/sit/screen/TextureButtonWidget.java new file mode 100644 index 0000000..122137b --- /dev/null +++ b/src/main/java/one/oth3r/sit/screen/TextureButtonWidget.java @@ -0,0 +1,85 @@ +package one.oth3r.sit.screen; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +public class TextureButtonWidget extends ButtonWidget { + //todo gray support + protected final Identifier texture; + protected final int textureWidth; + protected final int textureHeight; + protected final boolean tooltip; + + TextureButtonWidget(int width, int height, Text message, int textureWidth, int textureHeight, Identifier texture, ButtonWidget.PressAction onPress, @Nullable ButtonWidget.NarrationSupplier narrationSupplier, boolean tooltip) { + super(0, 0, width, height, message, onPress, narrationSupplier == null ? DEFAULT_NARRATION_SUPPLIER : narrationSupplier); + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + this.texture = texture; + this.tooltip = tooltip; + if (tooltip) setTooltip(Tooltip.of(message)); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + super.renderWidget(context, mouseX, mouseY, delta); + int x = this.getX() + this.getWidth() / 2 - this.textureWidth / 2; + int y = this.getY() + this.getHeight() / 2 - this.textureHeight / 2; + context.drawGuiTexture(this.texture, x, y, this.textureWidth, this.textureHeight); + } + + @Override + public void drawMessage(DrawContext context, TextRenderer textRenderer, int color) { + if (!this.tooltip) super.drawMessage(context, textRenderer, color); + } + + + public static class Builder { + private final Text text; + private final ButtonWidget.PressAction onPress; + private final boolean hideText; + private int width = 150; + private int height = 20; + @Nullable + private Identifier texture; + private int textureWidth; + private int textureHeight; + @Nullable + ButtonWidget.NarrationSupplier narrationSupplier; + + public Builder(Text text, ButtonWidget.PressAction onPress, boolean hideText) { + this.text = text; + this.onPress = onPress; + this.hideText = hideText; + } + + public Builder dimensions(int width, int height) { + this.width = width; + this.height = height; + return this; + } + + public Builder texture(Identifier texture, int width, int height) { + this.texture = texture; + this.textureWidth = width; + this.textureHeight = height; + return this; + } + + public Builder narration(ButtonWidget.NarrationSupplier narrationSupplier) { + this.narrationSupplier = narrationSupplier; + return this; + } + + public TextureButtonWidget build() { + if (this.texture == null) { + throw new IllegalStateException("Sprite not set"); + } + return new TextureButtonWidget(width,height,text,textureWidth,textureHeight,texture,onPress,narrationSupplier,hideText); + } + } +} diff --git a/src/main/java/one/oth3r/sit/screen/UnderConstructionScreen.java b/src/main/java/one/oth3r/sit/screen/UnderConstructionScreen.java new file mode 100644 index 0000000..763a585 --- /dev/null +++ b/src/main/java/one/oth3r/sit/screen/UnderConstructionScreen.java @@ -0,0 +1,70 @@ +package one.oth3r.sit.screen; + +import net.minecraft.client.gui.screen.ConfirmLinkScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.Util; +import one.oth3r.sit.file.CustomFile; +import one.oth3r.sit.utl.Data; + +import java.net.URI; +import java.nio.file.Paths; + +public class UnderConstructionScreen> extends Screen { + protected final Screen parent; + protected T file; + + public UnderConstructionScreen(Screen parent, T file) { + super(Text.translatable("screen.config")); + this.parent = parent; + this.file = file; + } + + @Override + protected void init() { + int startY = this.height / 5-4; + ButtonWidget foxPNG = this.addDrawableChild(new ClickableImageWidget(70,70,140,140, Tooltip.of(Text.of("Art by @bunnestbun")), + Identifier.of(Data.MOD_ID, "textures/gui/fox.png"), ConfirmLinkScreen.opening(this, URI.create("https://www.instagram.com/bunnestbun/")))); + foxPNG.setPosition(this.width / 2 - (foxPNG.getWidth()/2), startY-35); + + ButtonWidget openFileButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("gui.button.file"), + (button) -> Util.getOperatingSystem().open(this.file.getFile())) + .dimensions(0, 0, 118 ,20).build()); + openFileButton.setPosition(this.width / 2 - 70, startY+110); + + TextureButtonWidget folderButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("gui.button.folder"), + (button) -> Util.getOperatingSystem().open(Paths.get(this.file.getFile().getParent())), true) + .dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "folder"), 15, 15).build()); + folderButton.setPosition(this.width / 2 + 50, startY + 110); + + TextureButtonWidget resetButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("gui.button.reset"), + (button) -> { + this.file.reset(); + this.file.save(); + }, true) + .dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "reset_file"), 15, 15).build()); + resetButton.setPosition(this.width / 2 -70, startY + 135); + + ButtonWidget revertButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("gui.button.revert"), + (button) -> this.file.save()) + .dimensions(0, 0, 118,20).build()); + revertButton.setPosition(this.width / 2 - 48, startY+135); + + + ButtonWidget saveExitButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("gui.button.save"), + (button) -> { + this.file.save(); + this.client.setScreen(parent); + }) + .dimensions(0, 0, 140,20).build()); + saveExitButton.setPosition(this.width / 2 - 70, startY+168); + } + + @Override + public void close() { + this.client.setScreen(parent); + } +}