From e1410df385d40071cdc420d6c87e7ae3ad93d1af Mon Sep 17 00:00:00 2001 From: Vinrobot Date: Thu, 10 Aug 2023 21:46:04 +0200 Subject: [PATCH] Create config menu with ModMenu --- build.gradle | 8 ++ .../client/MinecraftEmoteModMenuApi.java | 15 +++ .../mcemote/client/widget/BaseScreen.java | 43 +++++++ .../client/widget/ConfigurationScreen.java | 106 ++++++++++++++++++ src/main/resources/fabric.mod.json | 3 + 5 files changed, 175 insertions(+) create mode 100644 src/client/java/net/vinrobot/mcemote/client/MinecraftEmoteModMenuApi.java create mode 100644 src/client/java/net/vinrobot/mcemote/client/widget/BaseScreen.java create mode 100644 src/client/java/net/vinrobot/mcemote/client/widget/ConfigurationScreen.java diff --git a/build.gradle b/build.gradle index 8805b81..107049f 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,12 @@ repositories { maven { url 'https://jitpack.io' } + maven { + url 'https://maven.terraformersmc.com/releases' + content { + includeGroup 'com.terraformersmc' + } + } } loom { @@ -47,6 +53,8 @@ dependencies { // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + modClientCompileOnly "com.terraformersmc:modmenu:7.2.1" + // WebP support for ImageIO, not fully working with animated WebP modImplementation "com.twelvemonkeys.imageio:imageio-webp:3.9.4" diff --git a/src/client/java/net/vinrobot/mcemote/client/MinecraftEmoteModMenuApi.java b/src/client/java/net/vinrobot/mcemote/client/MinecraftEmoteModMenuApi.java new file mode 100644 index 0000000..8b163a1 --- /dev/null +++ b/src/client/java/net/vinrobot/mcemote/client/MinecraftEmoteModMenuApi.java @@ -0,0 +1,15 @@ +package net.vinrobot.mcemote.client; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; +import net.vinrobot.mcemote.MinecraftEmote; +import net.vinrobot.mcemote.client.widget.ConfigurationScreen; +import net.vinrobot.mcemote.config.ConfigurationManager; + +public class MinecraftEmoteModMenuApi implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + final ConfigurationManager configManager = MinecraftEmote.getInstance().getConfigManager(); + return parent -> new ConfigurationScreen(parent, configManager); + } +} diff --git a/src/client/java/net/vinrobot/mcemote/client/widget/BaseScreen.java b/src/client/java/net/vinrobot/mcemote/client/widget/BaseScreen.java new file mode 100644 index 0000000..45e8bfd --- /dev/null +++ b/src/client/java/net/vinrobot/mcemote/client/widget/BaseScreen.java @@ -0,0 +1,43 @@ +package net.vinrobot.mcemote.client.widget; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.text.Text; + +public class BaseScreen extends Screen { + private final Screen parent; + + private static final int GRADIENT_START_COLOR = 0xFF000000; + private static final int GRADIENT_END_COLOR = 0x00000000; + + public BaseScreen(final Screen parent, final Text title) { + super(title); + this.parent = parent; + } + + @Override + public void close() { + this.client.setScreen(this.parent); + } + + public void renderBackground(final DrawContext context, final int marginTop, final int marginBottom) { + final int bottom = this.height - marginBottom; + + // Background (Middle) + context.setShaderColor(0.125F, 0.125F, 0.125F, 1.0F); + context.drawTexture(Screen.OPTIONS_BACKGROUND_TEXTURE, 0, marginTop, this.width, bottom, this.width, bottom - marginTop, 32, 32); + context.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + + // Background (Top & Bottom), based on Screen.renderBackgroundTexture(DrawContext) + context.setShaderColor(0.25F, 0.25F, 0.25F, 1.0F); + context.drawTexture(Screen.OPTIONS_BACKGROUND_TEXTURE, 0, 0, 0.0F, 0.0F, this.width, marginTop, 32, 32); + context.drawTexture(Screen.OPTIONS_BACKGROUND_TEXTURE, 0, bottom, 0.0F, bottom, this.width, this.height - bottom, 32, 32); + context.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + + // Gradients + final RenderLayer guiOverlay = RenderLayer.getGuiOverlay(); + context.fillGradient(guiOverlay, 0, marginTop, this.width, marginTop + 4, GRADIENT_START_COLOR, GRADIENT_END_COLOR, 0); + context.fillGradient(guiOverlay, 0, bottom - 4, this.width, bottom, GRADIENT_END_COLOR, GRADIENT_START_COLOR, 0); + } +} diff --git a/src/client/java/net/vinrobot/mcemote/client/widget/ConfigurationScreen.java b/src/client/java/net/vinrobot/mcemote/client/widget/ConfigurationScreen.java new file mode 100644 index 0000000..54bc5f1 --- /dev/null +++ b/src/client/java/net/vinrobot/mcemote/client/widget/ConfigurationScreen.java @@ -0,0 +1,106 @@ +package net.vinrobot.mcemote.client.widget; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; +import net.vinrobot.mcemote.config.Configuration; +import net.vinrobot.mcemote.config.ConfigurationManager; + +public class ConfigurationScreen extends BaseScreen { + private static final Text MENU_TITLE = Text.translatableWithFallback("mcemote.options.title", "Minecraft Emote Options"); + private static final Text TWITCH_ID_LABEL = Text.translatableWithFallback("mcemote.options.twitchId", "Twitch ID"); + + private static final int TITLE_COLOR = 0xFFFFFF; + private static final int LABEL_COLOR = 0xA0A0A0; + private static final int TEXTFIELD_VALID_COLOR = 0xE0E0E0; + private static final int TEXTFIELD_INVALID_COLOR = 0xFF0000; + + private final ConfigurationManager configManager; + + private ButtonWidget doneButton; + private TextFieldWidget twitchIdField; + + public ConfigurationScreen(final Screen parent, final ConfigurationManager configManager) { + super(parent, MENU_TITLE); + this.configManager = configManager; + } + + @Override + public void tick() { + super.tick(); + this.twitchIdField.tick(); + } + + @Override + protected void init() { + final int widgetWidth = 200; + final int widgetHeight = 20; + final int widgetX = (this.width - widgetWidth) / 2; + final Configuration config = this.configManager.getConfig(); + + this.twitchIdField = new TextFieldWidget(this.textRenderer, widgetX, 75, widgetWidth, widgetHeight, TWITCH_ID_LABEL); + this.twitchIdField.setMaxLength(32); + this.twitchIdField.setText(config.twitchId().get()); + this.twitchIdField.setChangedListener((value) -> this.validateInputs()); + this.addDrawableChild(this.twitchIdField); + + final int buttonSpacing = widgetHeight + 6; + int buttonY = this.height - 5; + + buttonY -= buttonSpacing; + this.doneButton = this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, this::saveAndClose) + .dimensions(widgetX, buttonY, widgetWidth, widgetHeight).build()); + + buttonY -= buttonSpacing; + this.addDrawableChild(ButtonWidget.builder(ScreenTexts.CANCEL, this::discardAndClose) + .dimensions(widgetX, buttonY, widgetWidth, widgetHeight).build()); + + this.validateInputs(); + } + + @Override + public void resize(MinecraftClient client, int width, int height) { + final String twitchIdValue = this.twitchIdField.getText(); + super.resize(client, width, height); + this.twitchIdField.setText(twitchIdValue); + } + + private void saveAndClose(final ButtonWidget ignored) { + final Configuration config = this.configManager.getConfig(); + + final String twitchIdValue = this.twitchIdField.getText(); + config.twitchId().set(twitchIdValue); + + this.configManager.save(); + this.close(); + } + + private void discardAndClose(final ButtonWidget ignored) { + this.close(); + } + + private void validateInputs() { + final Configuration config = this.configManager.getConfig(); + + final String twitchIdValue = this.twitchIdField.getText(); + final boolean isTwitchIdValid = twitchIdValue != null && config.twitchId().isValid(twitchIdValue); + + this.twitchIdField.setEditableColor(isTwitchIdValid ? TEXTFIELD_VALID_COLOR : TEXTFIELD_INVALID_COLOR); + + this.doneButton.active = isTwitchIdValid; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + this.renderBackground(context, 41, 67); + + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, TITLE_COLOR); + context.drawTextWithShadow(this.textRenderer, TWITCH_ID_LABEL, this.width / 2 - 100, 60, LABEL_COLOR); + + super.render(context, mouseX, mouseY, delta); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f585afb..8b1dd09 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,6 +21,9 @@ ], "client": [ "net.vinrobot.mcemote.client.MinecraftEmoteModClient" + ], + "modmenu": [ + "net.vinrobot.mcemote.client.MinecraftEmoteModMenuApi" ] }, "accessWidener": "mcemote.accesswidener",