From e421b1a5a0cf1451a90a12de55ccd180014ed4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A4seToatz?= Date: Mon, 3 Nov 2025 23:50:02 +0100 Subject: [PATCH] more options --- .../com/kasetoatz/fastGhast/FastGhast.java | 4 +- .../fastGhast/configscreen/ConfigEntry.java | 14 ++++ .../configscreen/ConfigEntryList.java | 5 +- .../fastGhast/configscreen/ConfigScreen.java | 9 +-- .../fastGhast/configscreen/DumbassConfig.java | 15 ++++ .../fastGhast/configscreen/InputField.java | 69 +++++++++++++++++++ .../configscreen/options/BoolOption.java | 16 ++--- .../configscreen/options/FloatOption.java | 26 ++++--- .../configscreen/options/InputOption.java | 46 +++++++++++++ .../configscreen/options/Option.java | 20 +----- .../configscreen/options/Validator.java | 23 ------- .../options/validators/RangeValidator.java | 46 +++++++++++++ .../options/validators/Validator.java | 7 ++ 13 files changed, 229 insertions(+), 71 deletions(-) create mode 100644 src/main/java/com/kasetoatz/fastGhast/configscreen/InputField.java create mode 100644 src/main/java/com/kasetoatz/fastGhast/configscreen/options/InputOption.java delete mode 100644 src/main/java/com/kasetoatz/fastGhast/configscreen/options/Validator.java create mode 100644 src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/RangeValidator.java create mode 100644 src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/Validator.java diff --git a/src/main/java/com/kasetoatz/fastGhast/FastGhast.java b/src/main/java/com/kasetoatz/fastGhast/FastGhast.java index 8979e3c..330f49f 100644 --- a/src/main/java/com/kasetoatz/fastGhast/FastGhast.java +++ b/src/main/java/com/kasetoatz/fastGhast/FastGhast.java @@ -3,7 +3,7 @@ package com.kasetoatz.fastghast; import com.kasetoatz.fastghast.configscreen.DumbassConfig; import com.kasetoatz.fastghast.configscreen.options.BoolOption; import com.kasetoatz.fastghast.configscreen.options.FloatOption; -import com.kasetoatz.fastghast.configscreen.options.Validator; +import com.kasetoatz.fastghast.configscreen.options.validators.RangeValidator; import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; import net.fabricmc.api.ModInitializer; @@ -35,7 +35,7 @@ public class Fastghast implements ModInitializer, ModMenuApi { return DumbassConfig.builder() .withOption(new BoolOption("Test Boolean Option", "test_bool_opt", false)) - .withOption(new FloatOption("Test Float Option", "test_float_opt", 1.F, value -> new Validator(value > 0.F, "Number must be binger than 0."))) + .withOption(new FloatOption("Test Float Option", "test_float_opt", 1.F, new RangeValidator<>(0.F, null))) ::build; } } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntry.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntry.java index 3f70da6..0a8f8cb 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntry.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntry.java @@ -3,11 +3,15 @@ package com.kasetoatz.fastghast.configscreen; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget; import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.gui.widget.TextWidget; import java.util.List; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.*; + public class ConfigEntry extends ElementListWidget.Entry { private final List widgets; @@ -40,6 +44,16 @@ public class ConfigEntry extends ElementListWidget.Entry { for (ClickableWidget widget : widgets) { + if (widget instanceof TextWidget) + { + widget.setX(TEXT_LEFT); + widget.setDimensions(TEXT_WIDTH, TEXT_HEIGHT); + } + else if (widget instanceof ButtonWidget || widget instanceof InputField) + { + widget.setX(this.getWidth() - OPTION_RIGHT); + widget.setDimensions(OPTION_WIDTH, OPTION_HEIGHT); + } widget.setY(this.getY() + (this.getHeight() - widget.getHeight()) / 2); widget.render(context, mouseX, mouseY, deltaTicks); } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntryList.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntryList.java index 305fcd8..602a597 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntryList.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigEntryList.java @@ -7,6 +7,9 @@ import net.minecraft.client.gui.widget.*; import java.util.List; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BACKGROUND_COLOR_1; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BACKGROUND_COLOR_2; + public class ConfigEntryList extends ElementListWidget { public ConfigEntryList(MinecraftClient client, int width, int height, int y, int itemHeight) @@ -41,7 +44,7 @@ public class ConfigEntryList extends ElementListWidget { break; } - context.fill(0, Math.max(option.getY(), this.getY()), option.getWidth() + 30, Math.min(option.getY() + option.getHeight(), this.getY() + this.height), (i % 2 == 0) ? 0x50555555 : 0x50333333); + context.fill(0, Math.max(option.getY(), this.getY()), option.getWidth() + 30, Math.min(option.getY() + option.getHeight(), this.getY() + this.height), (i % 2 == 0) ? BACKGROUND_COLOR_1 : BACKGROUND_COLOR_2); } super.renderWidget(context, mouseX, mouseY, delta); } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigScreen.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigScreen.java index 9bbc14d..f555fc8 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigScreen.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/ConfigScreen.java @@ -3,14 +3,15 @@ package com.kasetoatz.fastghast.configscreen; import com.kasetoatz.fastghast.configscreen.options.Option; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.client.gui.widget.ThreePartsLayoutWidget; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; -import java.util.ArrayList; import java.util.List; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.DONE_BUTTON_WIDTH; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.ENTRY_HEIGHT; + public class ConfigScreen extends Screen { private final Screen parent; @@ -29,13 +30,13 @@ public class ConfigScreen extends Screen protected void init() { this.layout.addHeader(this.title, this.textRenderer); - this.body = new ConfigEntryList(this.client, this.layout.getWidth(), this.layout.getContentHeight(), this.layout.getHeaderHeight(), 50); + this.body = new ConfigEntryList(this.client, this.layout.getWidth(), this.layout.getContentHeight(), this.layout.getHeaderHeight(), ENTRY_HEIGHT); for (Option option : this.options) { this.body.add(option); } this.layout.addBody(body); - this.layout.addFooter(ButtonWidget.builder(ScreenTexts.DONE, button -> this.close()).width(200).build()); + this.layout.addFooter(ButtonWidget.builder(ScreenTexts.DONE, button -> this.close()).width(DONE_BUTTON_WIDTH).build()); this.layout.forEachChild(this::addDrawableChild); this.refreshWidgetPositions(); } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/DumbassConfig.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/DumbassConfig.java index f96c771..289b8e0 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/DumbassConfig.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/DumbassConfig.java @@ -8,6 +8,21 @@ import java.util.ArrayList; public class DumbassConfig { + public static int TEXT_LEFT = 20; + public static int TEXT_WIDTH = 200; + public static int TEXT_HEIGHT = 40; + public static int OPTION_RIGHT = 100; + public static int OPTION_WIDTH = 80; + public static int OPTION_HEIGHT = 40; + public static int ENTRY_HEIGHT = 50; + public static int DONE_BUTTON_WIDTH = 200; + public static int BOOLEAN_TRUE_COLOR = 0x00FF00; + public static int BOOLEAN_FALSE_COLOR = 0xFF0000; + public static int VALID_INPUT_COLOR = 0xFFFFFFFF; + public static int INVALID_INPUT_COLOR = 0xFFFF0000; + public static int BACKGROUND_COLOR_1 = 0x50555555; + public static int BACKGROUND_COLOR_2 = 0x50333333; + public static Builder builder() { return new Builder(); diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/InputField.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/InputField.java new file mode 100644 index 0000000..72b80e0 --- /dev/null +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/InputField.java @@ -0,0 +1,69 @@ +package com.kasetoatz.fastghast.configscreen; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ButtonTextures; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.lang.reflect.Field; + +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.INVALID_INPUT_COLOR; + +public class InputField extends TextFieldWidget +{ + private boolean valid = true; + private final ButtonTextures textures = new ButtonTextures(Identifier.ofVanilla("widget/text_field"), Identifier.ofVanilla("widget/text_field_highlighted")); + private Field textX; + private Field textY; + + public InputField(TextRenderer textRenderer, Text text) + { + super(textRenderer, 80, 40, text); + initTextPosition(); + } + + private void initTextPosition() + { + try + { + this.textX = TextFieldWidget.class.getDeclaredField("textX"); + this.textY = TextFieldWidget.class.getDeclaredField("textY"); + this.textX.setAccessible(true); + this.textY.setAccessible(true); + } + catch (NoSuchFieldException ignored) {} + } + + private void updateTextPosition() + { + if (this.textX != null && this.textY != null) + { + try + { + this.textX.setInt(this, this.getX() + 4); + this.textY.setInt(this, this.getY() + (this.height - 8) / 2); + } + catch (IllegalAccessException ignored) {} + } + } + + public void setValid(boolean valid) + { + this.valid = valid; + this.setDrawsBackground(valid); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) + { + if (!this.valid) + { + updateTextPosition(); + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, textures.get(this.isInteractable(), this.isFocused()), super.getX(), super.getY(), this.getWidth(), this.getHeight(), INVALID_INPUT_COLOR); + } + super.renderWidget(context, mouseX, mouseY, delta); + } +} diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/BoolOption.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/BoolOption.java index 009518d..7bc7398 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/BoolOption.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/BoolOption.java @@ -6,6 +6,9 @@ import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.text.Text; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BOOLEAN_FALSE_COLOR; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.BOOLEAN_TRUE_COLOR; + public class BoolOption extends Option { public BoolOption(String text, String key, boolean defaultValue) @@ -15,12 +18,12 @@ public class BoolOption extends Option private Text getButtonText() { - return this.getValue() ? Text.literal("True").withColor(0x00FF00) : Text.literal("False").withColor(0xFF0000); + return this.getValue() ? Text.literal("True").withColor(BOOLEAN_TRUE_COLOR) : Text.literal("False").withColor(BOOLEAN_FALSE_COLOR); } private void onClick(ButtonWidget button) { - this.onChange(!this.getValue()); + this.setValue(!this.getValue()); button.setMessage(this.getButtonText()); } @@ -28,13 +31,8 @@ public class BoolOption extends Option public ConfigEntry toEntry(TextRenderer textRenderer, int maxWidth) { return new ConfigEntry( - new TextWidget(20, 0, 200, 40, this.getText(), textRenderer), - ButtonWidget.builder(getButtonText(), this::onClick).dimensions(maxWidth - 100, 0, 80, 40).build() + new TextWidget(this.getText(), textRenderer), + ButtonWidget.builder(getButtonText(), this::onClick).build() ); } - - @Override - public void onError(String message) - { - } } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/FloatOption.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/FloatOption.java index 84c4730..08b2aa8 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/FloatOption.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/FloatOption.java @@ -1,20 +1,23 @@ package com.kasetoatz.fastghast.configscreen.options; import com.kasetoatz.fastghast.configscreen.ConfigEntry; +import com.kasetoatz.fastghast.configscreen.InputField; +import com.kasetoatz.fastghast.configscreen.options.validators.Validator; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.gui.widget.TextWidget; -import net.minecraft.text.Text; -import java.util.function.Function; - -public class FloatOption extends Option +public class FloatOption extends InputOption { - public FloatOption(String text, String key, Float defaultValue, Function validator) + public FloatOption(String text, String key, Float defaultValue, Validator validator) { super(text, key, defaultValue, validator); } + public FloatOption(String text, String key, Float defaultValue) + { + super(text, key, defaultValue); + } + private boolean predicate(String text) { if (text.isEmpty() || text.equals(".") || text.equals("-")) @@ -35,18 +38,13 @@ public class FloatOption extends Option @Override public ConfigEntry toEntry(TextRenderer textRenderer, int maxWidth) { - TextFieldWidget textField = new TextFieldWidget(textRenderer, maxWidth - 100, 0, 80, 40, this.getText()); + this.textField = new InputField(textRenderer, this.getText()); textField.setText(this.getValue().toString()); textField.setTextPredicate(this::predicate); + textField.setChangedListener(text -> this.onChange((text.isEmpty() || text.equals(".") || text.equals("-")) ? 0.F : Float.parseFloat(text))); return new ConfigEntry( - new TextWidget(20, 0, 200, 40, this.getText(), textRenderer), + new TextWidget(this.getText(), textRenderer), textField ); } - - @Override - public void onError(String message) - { - - } } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/InputOption.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/InputOption.java new file mode 100644 index 0000000..19eafbf --- /dev/null +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/InputOption.java @@ -0,0 +1,46 @@ +package com.kasetoatz.fastghast.configscreen.options; + +import com.kasetoatz.fastghast.configscreen.InputField; +import com.kasetoatz.fastghast.configscreen.options.validators.Validator; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.text.Text; + +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.INVALID_INPUT_COLOR; +import static com.kasetoatz.fastghast.configscreen.DumbassConfig.VALID_INPUT_COLOR; + +public abstract class InputOption extends Option +{ + public InputField textField; + private Validator validator; + + public InputOption(String text, String key, T defaultValue, Validator validator) + { + super(text, key, defaultValue); + this.validator = validator; + } + + public InputOption(String text, String key, T defaultValue) + { + super(text, key, defaultValue); + } + + public void onChange(T value) + { + if (validator != null && !validator.isValid(value)) + { + onError(validator.getErrorMessage()); + return; + } + this.textField.setValid(true); + this.textField.setEditableColor(VALID_INPUT_COLOR); + this.textField.setTooltip(null); + this.setValue(value); + } + + public void onError(String message) + { + this.textField.setValid(false); + this.textField.setEditableColor(INVALID_INPUT_COLOR); + this.textField.setTooltip(Tooltip.of(Text.literal(message).withColor(INVALID_INPUT_COLOR))); + } +} diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Option.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Option.java index 19de6b9..31370cb 100644 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Option.java +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Option.java @@ -4,30 +4,21 @@ import com.kasetoatz.fastghast.configscreen.ConfigEntry; import net.minecraft.client.font.TextRenderer; import net.minecraft.text.Text; -import java.util.function.Function; - public abstract class Option { private final Text text; private final String key; private final T defaultValue; - private final Function validator; private T value; - public Option(String text, String key, T defaultValue, Function validator) + public Option(String text, String key, T defaultValue) { this.text = Text.of(text); this.key = key; this.defaultValue = defaultValue; - this.validator = validator; this.value = defaultValue; } - public Option(String text, String key, T defaultValue) - { - this(text, key, defaultValue, value -> new Validator(true, "")); - } - public Text getText() { return this.text; @@ -48,17 +39,10 @@ public abstract class Option return this.value; } - public void onChange(T value) + public void setValue(T value) { - Validator validator = this.validator.apply(value); - if (!validator.isValid()) - { - onError(validator.getErrorMessage()); - return; - } this.value = value; } public abstract ConfigEntry toEntry(TextRenderer textRenderer, int maxWidth); - public abstract void onError(String message); } diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Validator.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Validator.java deleted file mode 100644 index b714401..0000000 --- a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/Validator.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.kasetoatz.fastghast.configscreen.options; - -public class Validator -{ - private final boolean valid; - private final String errorMessage; - - public Validator(boolean condition, String errorMessage) - { - this.valid = condition; - this.errorMessage = errorMessage; - } - - public boolean isValid() - { - return this.valid; - } - - public String getErrorMessage() - { - return this.errorMessage; - } -} diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/RangeValidator.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/RangeValidator.java new file mode 100644 index 0000000..679ad29 --- /dev/null +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/RangeValidator.java @@ -0,0 +1,46 @@ +package com.kasetoatz.fastghast.configscreen.options.validators; + +public class RangeValidator> extends Validator +{ + private final T min; + private final T max; + + public RangeValidator(T minInclusive, T maxInclusive) + { + if (minInclusive == null && maxInclusive == null) + { + throw new IllegalArgumentException("Min and max cannot both be null"); + } + if (minInclusive != null && maxInclusive != null && minInclusive.compareTo(maxInclusive) > 0) + { + throw new IllegalArgumentException("Min cannot be greater than max"); + } + this.min = minInclusive; + this.max = maxInclusive; + } + + @Override + public boolean isValid(T value) + { + return ((min == null) || value.compareTo(min) > 0) && ((max == null) || value.compareTo(max) < 0); + } + + @Override + public String getErrorMessage() + { + String error = "Number must be "; + if (min == null && max != null) + { + error += "smaller than " + max; + } + else if (min != null && max == null) + { + error += "larger than " + min; + } + else + { + error += "between " + min + " and " + max; + } + return error; + } +} diff --git a/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/Validator.java b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/Validator.java new file mode 100644 index 0000000..36889bd --- /dev/null +++ b/src/main/java/com/kasetoatz/fastGhast/configscreen/options/validators/Validator.java @@ -0,0 +1,7 @@ +package com.kasetoatz.fastghast.configscreen.options.validators; + +public abstract class Validator +{ + public abstract boolean isValid(T value); + public abstract String getErrorMessage(); +}