aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle.kts2
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java4
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java3
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java21
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java4
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java8
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java2
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java2
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java2
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java2
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java6
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java12
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java5
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java91
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java105
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java105
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java104
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java104
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java69
-rw-r--r--src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java10
-rw-r--r--src/testmod/java/dev/isxander/yacl/test/GuiTest.java43
-rw-r--r--src/testmod/java/dev/isxander/yacl/test/config/ConfigData.java4
22 files changed, 644 insertions, 64 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index 4a47fb0..1ece3df 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -64,7 +64,7 @@ val fabricLoaderVersion: String by project
dependencies {
minecraft("com.mojang:minecraft:$minecraftVersion")
- mappings("net.fabricmc:yarn:$minecraftVersion+build.1:v2")
+ mappings("net.fabricmc:yarn:$minecraftVersion+build.2:v2")
modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion")
"modClientImplementation"(fabricApi.module("fabric-resource-loader-v0", "0.68.1+1.19.3"))
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java b/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java
index b8e2cd1..7666dff 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/ActionController.java
@@ -5,8 +5,8 @@ import dev.isxander.yacl.api.Controller;
import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.AbstractWidget;
import dev.isxander.yacl.gui.YACLScreen;
+import net.minecraft.client.util.InputUtil;
import net.minecraft.text.Text;
-import org.lwjgl.glfw.GLFW;
import java.util.function.BiConsumer;
@@ -94,7 +94,7 @@ public class ActionController implements Controller<BiConsumer<YACLScreen, Butto
return false;
}
- if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
+ if (keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_SPACE || keyCode == InputUtil.GLFW_KEY_KP_ENTER) {
executeAction();
return true;
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java
index b696831..3a8e5c3 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/BooleanController.java
@@ -5,6 +5,7 @@ import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.AbstractWidget;
import dev.isxander.yacl.gui.YACLScreen;
+import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.Text;
@@ -146,7 +147,7 @@ public class BooleanController implements Controller<Boolean> {
return false;
}
- if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
+ if (keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_SPACE || keyCode == InputUtil.GLFW_KEY_KP_ENTER) {
toggleSetting();
return true;
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java b/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java
index a68475d..6853a03 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/ColorController.java
@@ -108,7 +108,7 @@ public class ColorController implements IStringController<Color> {
private final List<Character> allowedChars;
public ColorControllerElement(ColorController control, YACLScreen screen, Dimension<Integer> dim) {
- super(control, screen, dim);
+ super(control, screen, dim, true);
this.colorController = control;
this.allowedChars = ImmutableList.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
}
@@ -135,21 +135,22 @@ public class ColorController implements IStringController<Color> {
if (caretPos == 0)
return;
- string = string.substring(0, Math.min(inputField.length() - caretPos, string.length()));
+ String trimmed = string.substring(0, Math.min(inputField.length() - caretPos, string.length()));
- inputField.replace(caretPos, caretPos + string.length(), string);
- caretPos += string.length();
- setSelectionLength();
-
- updateControl();
+ if (modifyInput(builder -> builder.replace(caretPos, caretPos + trimmed.length(), trimmed))) {
+ caretPos += trimmed.length();
+ setSelectionLength();
+ updateControl();
+ }
}
@Override
protected void doBackspace() {
if (caretPos > 1) {
- inputField.setCharAt(caretPos - 1, '0');
- caretPos--;
- updateControl();
+ if (modifyInput(builder -> builder.setCharAt(caretPos - 1, '0'))) {
+ caretPos--;
+ updateControl();
+ }
}
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java b/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
index 340983d..b0ae449 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
@@ -6,9 +6,9 @@ import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.AbstractWidget;
import dev.isxander.yacl.gui.YACLScreen;
import net.minecraft.client.gui.DrawableHelper;
+import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
-import org.lwjgl.glfw.GLFW;
/**
* This controller renders a tickbox
@@ -109,7 +109,7 @@ public class TickBoxController implements Controller<Boolean> {
return false;
}
- if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_SPACE || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
+ if (keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_SPACE || keyCode == InputUtil.GLFW_KEY_KP_ENTER) {
toggleSetting();
return true;
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java
index ab0a9c3..246fbec 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/cycling/CyclingControllerElement.java
@@ -4,7 +4,7 @@ import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.YACLScreen;
import dev.isxander.yacl.gui.controllers.ControllerWidget;
import net.minecraft.client.gui.screen.Screen;
-import org.lwjgl.glfw.GLFW;
+import net.minecraft.client.util.InputUtil;
public class CyclingControllerElement extends ControllerWidget<ICyclingController<?>> {
@@ -39,11 +39,11 @@ public class CyclingControllerElement extends ControllerWidget<ICyclingControlle
return false;
switch (keyCode) {
- case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN ->
+ case InputUtil.GLFW_KEY_LEFT, InputUtil.GLFW_KEY_DOWN ->
cycleValue(-1);
- case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP ->
+ case InputUtil.GLFW_KEY_RIGHT, InputUtil.GLFW_KEY_UP ->
cycleValue(1);
- case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_SPACE, GLFW.GLFW_KEY_KP_ENTER ->
+ case InputUtil.GLFW_KEY_ENTER, InputUtil.GLFW_KEY_SPACE, InputUtil.GLFW_KEY_KP_ENTER ->
cycleValue(Screen.hasControlDown() || Screen.hasShiftDown() ? -1 : 1);
default -> {
return false;
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java
index b530e8c..54c7476 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/slider/DoubleSliderController.java
@@ -13,7 +13,7 @@ public class DoubleSliderController implements ISliderController<Double> {
/**
* Formats doubles to two decimal places
*/
- public static final Function<Double, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.2f", value));
+ public static final Function<Double, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.2f", value).replaceAll("[\u00a0\u202F]", " "));
private final Option<Double> option;
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java
index d7c203e..84ca9a2 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/slider/FloatSliderController.java
@@ -13,7 +13,7 @@ public class FloatSliderController implements ISliderController<Float> {
/**
* Formats floats to one decimal place
*/
- public static final Function<Float, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.1f", value));
+ public static final Function<Float, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,.1f", value).replaceAll("[\u00a0\u202F]", " "));
private final Option<Float> option;
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java
index a8bca7c..50ec9d2 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/slider/IntegerSliderController.java
@@ -10,7 +10,7 @@ import java.util.function.Function;
* {@link ISliderController} for integers.
*/
public class IntegerSliderController implements ISliderController<Integer> {
- public static final Function<Integer, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value));
+ public static final Function<Integer, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value).replaceAll("[\u00a0\u202F]", " "));
private final Option<Integer> option;
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java
index 50559d5..3038402 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/slider/LongSliderController.java
@@ -10,7 +10,7 @@ import java.util.function.Function;
* {@link ISliderController} for longs.
*/
public class LongSliderController implements ISliderController<Long> {
- public static final Function<Long, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value));
+ public static final Function<Long, Text> DEFAULT_FORMATTER = value -> Text.of(String.format("%,d", value).replaceAll("[\u00a0\u202F]", " "));
private final Option<Long> option;
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
index 913cc00..c78e0eb 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
@@ -5,9 +5,9 @@ import dev.isxander.yacl.gui.YACLScreen;
import dev.isxander.yacl.gui.controllers.ControllerWidget;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
-import org.lwjgl.glfw.GLFW;
public class SliderControllerElement extends ControllerWidget<ISliderController<?>> {
private final double min, max, interval;
@@ -104,8 +104,8 @@ public class SliderControllerElement extends ControllerWidget<ISliderController<
return false;
switch (keyCode) {
- case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> incrementValue(-1);
- case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> incrementValue(1);
+ case InputUtil.GLFW_KEY_LEFT, InputUtil.GLFW_KEY_DOWN -> incrementValue(-1);
+ case InputUtil.GLFW_KEY_RIGHT, InputUtil.GLFW_KEY_UP -> incrementValue(1);
default -> {
return false;
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java
index 41843b8..553e278 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/IStringController.java
@@ -2,6 +2,9 @@ package dev.isxander.yacl.gui.controllers.string;
import dev.isxander.yacl.api.Controller;
import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.api.utils.Dimension;
+import dev.isxander.yacl.gui.AbstractWidget;
+import dev.isxander.yacl.gui.YACLScreen;
import net.minecraft.text.Text;
/**
@@ -29,4 +32,13 @@ public interface IStringController<T> extends Controller<T> {
default Text formatValue() {
return Text.of(getString());
}
+
+ default boolean isInputValid(String input) {
+ return true;
+ }
+
+ @Override
+ default AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
+ return new StringControllerElement(this, screen, widgetDimension, true);
+ }
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java
index 0caaa93..3a07641 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringController.java
@@ -37,9 +37,4 @@ public class StringController implements IStringController<String> {
public void setFromString(String value) {
option().requestSet(value);
}
-
- @Override
- public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
- return new StringControllerElement(this, screen, widgetDimension);
- }
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java
index 0c3b7c9..bce6906 100644
--- a/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java
@@ -5,13 +5,17 @@ import dev.isxander.yacl.gui.YACLScreen;
import dev.isxander.yacl.gui.controllers.ControllerWidget;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
-import org.lwjgl.glfw.GLFW;
+
+import java.util.function.Consumer;
public class StringControllerElement extends ControllerWidget<IStringController<?>> {
- protected StringBuilder inputField;
+ protected final boolean instantApply;
+
+ protected String inputField;
protected Dimension<Integer> inputFieldBounds;
protected boolean inputFieldFocused;
@@ -22,12 +26,14 @@ public class StringControllerElement extends ControllerWidget<IStringController<
private final Text emptyText;
- public StringControllerElement(IStringController<?> control, YACLScreen screen, Dimension<Integer> dim) {
+ public StringControllerElement(IStringController<?> control, YACLScreen screen, Dimension<Integer> dim, boolean instantApply) {
super(control, screen, dim);
- inputField = new StringBuilder(control.getString());
+ this.instantApply = instantApply;
+ inputField = control.getString();
inputFieldFocused = false;
selectionLength = 0;
emptyText = Text.literal("Click to type...").formatted(Formatting.GRAY);
+ control.option().addListener((opt, val) -> inputField = control.getString());
setDimension(dim);
}
@@ -35,12 +41,14 @@ public class StringControllerElement extends ControllerWidget<IStringController<
protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) {
ticks += delta;
+ String text = instantApply ? control.getString() : inputField;
+
DrawableHelper.fill(matrices, inputFieldBounds.x(), inputFieldBounds.yLimit(), inputFieldBounds.xLimit(), inputFieldBounds.yLimit() + 1, -1);
DrawableHelper.fill(matrices, inputFieldBounds.x() + 1, inputFieldBounds.yLimit() + 1, inputFieldBounds.xLimit() + 1, inputFieldBounds.yLimit() + 2, 0xFF404040);
if (inputFieldFocused || focused) {
- int caretX = inputFieldBounds.x() + textRenderer.getWidth(control.getString().substring(0, caretPos)) - 1;
- if (inputField.isEmpty())
+ int caretX = inputFieldBounds.x() + textRenderer.getWidth(text.substring(0, caretPos)) - 1;
+ if (text.isEmpty())
caretX += inputFieldBounds.width() / 2;
if (ticks % 20 <= 10) {
@@ -48,7 +56,7 @@ public class StringControllerElement extends ControllerWidget<IStringController<
}
if (selectionLength != 0) {
- int selectionX = inputFieldBounds.x() + textRenderer.getWidth(control.getString().substring(0, caretPos + selectionLength));
+ int selectionX = inputFieldBounds.x() + textRenderer.getWidth(text.substring(0, caretPos + selectionLength));
DrawableHelper.fill(matrices, caretX, inputFieldBounds.y() - 1, selectionX, inputFieldBounds.yLimit(), 0x803030FF);
}
}
@@ -83,11 +91,11 @@ public class StringControllerElement extends ControllerWidget<IStringController<
return false;
switch (keyCode) {
- case GLFW.GLFW_KEY_ESCAPE -> {
- inputFieldFocused = false;
+ case InputUtil.GLFW_KEY_ESCAPE, InputUtil.GLFW_KEY_ENTER -> {
+ unfocus();
return true;
}
- case GLFW.GLFW_KEY_LEFT -> {
+ case InputUtil.GLFW_KEY_LEFT -> {
if (Screen.hasShiftDown()) {
if (Screen.hasControlDown()) {
int spaceChar = findSpaceIndex(true);
@@ -98,14 +106,18 @@ public class StringControllerElement extends ControllerWidget<IStringController<
selectionLength += 1;
}
} else {
- if (caretPos > 0)
- caretPos--;
+ if (caretPos > 0) {
+ if (selectionLength != 0)
+ caretPos += Math.min(selectionLength, 0);
+ else
+ caretPos--;
+ }
selectionLength = 0;
}
return true;
}
- case GLFW.GLFW_KEY_RIGHT -> {
+ case InputUtil.GLFW_KEY_RIGHT -> {
if (Screen.hasShiftDown()) {
if (Screen.hasControlDown()) {
int spaceChar = findSpaceIndex(false);
@@ -116,18 +128,22 @@ public class StringControllerElement extends ControllerWidget<IStringController<
selectionLength -= 1;
}
} else {
- if (caretPos < inputField.length())
- caretPos++;
+ if (caretPos < inputField.length()) {
+ if (selectionLength != 0)
+ caretPos += Math.max(selectionLength, 0);
+ else
+ caretPos++;
+ }
selectionLength = 0;
}
return true;
}
- case GLFW.GLFW_KEY_BACKSPACE -> {
+ case InputUtil.GLFW_KEY_BACKSPACE -> {
doBackspace();
return true;
}
- case GLFW.GLFW_KEY_DELETE -> {
+ case InputUtil.GLFW_KEY_DELETE -> {
doDelete();
return true;
}
@@ -172,36 +188,46 @@ public class StringControllerElement extends ControllerWidget<IStringController<
if (selectionLength != 0) {
write("");
} else if (caretPos > 0) {
- inputField.deleteCharAt(caretPos - 1);
- caretPos--;
- updateControl();
+ if (modifyInput(builder -> builder.deleteCharAt(caretPos - 1)))
+ caretPos--;
}
}
protected void doDelete() {
if (caretPos < inputField.length()) {
- inputField.deleteCharAt(caretPos);
- updateControl();
+ modifyInput(builder -> builder.deleteCharAt(caretPos));
}
}
public void write(String string) {
if (selectionLength == 0) {
- string = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField.toString()));
+ String trimmed = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField));
- inputField.insert(caretPos, string);
- caretPos += string.length();
+ if (modifyInput(builder -> builder.insert(caretPos, trimmed))) {
+ caretPos += trimmed.length();
+ }
} else {
int start = getSelectionStart();
int end = getSelectionEnd();
- string = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField.toString()) + textRenderer.getWidth(inputField.substring(start, end)));
+ String trimmed = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField) + textRenderer.getWidth(inputField.substring(start, end)));
- inputField.replace(start, end, string);
- caretPos = start + string.length();
- selectionLength = 0;
+ if (modifyInput(builder -> builder.replace(start, end, trimmed))) {
+ caretPos = start + trimmed.length();
+ selectionLength = 0;
+ }
}
- updateControl();
+ }
+
+ public boolean modifyInput(Consumer<StringBuilder> consumer) {
+ StringBuilder temp = new StringBuilder(inputField);
+ consumer.accept(temp);
+ if (!control.isInputValid(temp.toString()))
+ return false;
+ inputField = temp.toString();
+ if (instantApply)
+ updateControl();
+ return true;
}
public int getMaxLength() {
@@ -249,6 +275,7 @@ public class StringControllerElement extends ControllerWidget<IStringController<
public void unfocus() {
super.unfocus();
inputFieldFocused = false;
+ if (!instantApply) updateControl();
}
@Override
@@ -265,7 +292,7 @@ public class StringControllerElement extends ControllerWidget<IStringController<
}
protected void updateControl() {
- control.setFromString(inputField.toString());
+ control.setFromString(inputField);
}
@Override
@@ -278,6 +305,6 @@ public class StringControllerElement extends ControllerWidget<IStringController<
if (!inputFieldFocused && inputField.isEmpty())
return emptyText;
- return super.getValueText();
+ return instantApply || !inputFieldFocused ? control.formatValue() : Text.of(inputField);
}
}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java
new file mode 100644
index 0000000..1dbd7c0
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/DoubleFieldController.java
@@ -0,0 +1,105 @@
+package dev.isxander.yacl.gui.controllers.string.number;
+
+import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.gui.controllers.slider.DoubleSliderController;
+import net.minecraft.text.Text;
+
+import java.math.BigDecimal;
+import java.util.function.Function;
+
+/**
+ * {@inheritDoc}
+ */
+public class DoubleFieldController extends NumberFieldController<Double> {
+ private final double min, max;
+
+ /**
+ * Constructs a double field controller
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ * @param formatter display text, not used whilst editing
+ */
+ public DoubleFieldController(Option<Double> option, double min, double max, Function<Double, Text> formatter) {
+ super(option, formatter);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link DoubleSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ */
+ public DoubleFieldController(Option<Double> option, double min, double max) {
+ this(option, min, max, DoubleSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ * @param formatter display text, not used whilst editing
+ */
+ public DoubleFieldController(Option<Double> option, Function<Double, Text> formatter) {
+ this(option, -Double.MAX_VALUE, Double.MAX_VALUE, formatter);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link DoubleSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ */
+ public DoubleFieldController(Option<Double> option) {
+ this(option, -Double.MAX_VALUE, Double.MAX_VALUE, DoubleSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double min() {
+ return this.min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double max() {
+ return this.max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getString() {
+ return BigDecimal.valueOf(option().pendingValue()).stripTrailingZeros().toPlainString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPendingValue(double value) {
+ option().requestSet(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double pendingValue() {
+ return option().pendingValue();
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java
new file mode 100644
index 0000000..4b34d7f
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/FloatFieldController.java
@@ -0,0 +1,105 @@
+package dev.isxander.yacl.gui.controllers.string.number;
+
+import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.gui.controllers.slider.FloatSliderController;
+import net.minecraft.text.Text;
+
+import java.math.BigDecimal;
+import java.util.function.Function;
+
+/**
+ * {@inheritDoc}
+ */
+public class FloatFieldController extends NumberFieldController<Float> {
+ private final float min, max;
+
+ /**
+ * Constructs a double field controller
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ * @param formatter display text, not used whilst editing
+ */
+ public FloatFieldController(Option<Float> option, float min, float max, Function<Float, Text> formatter) {
+ super(option, formatter);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link FloatSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ */
+ public FloatFieldController(Option<Float> option, float min, float max) {
+ this(option, min, max, FloatSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ * @param formatter display text, not used whilst editing
+ */
+ public FloatFieldController(Option<Float> option, Function<Float, Text> formatter) {
+ this(option, -Float.MAX_VALUE, Float.MAX_VALUE, formatter);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link FloatSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ */
+ public FloatFieldController(Option<Float> option) {
+ this(option, -Float.MAX_VALUE, Float.MAX_VALUE, FloatSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double min() {
+ return this.min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double max() {
+ return this.max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getString() {
+ return BigDecimal.valueOf(option().pendingValue()).stripTrailingZeros().toPlainString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPendingValue(double value) {
+ option().requestSet((float) value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double pendingValue() {
+ return option().pendingValue();
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java
new file mode 100644
index 0000000..5f0121a
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/IntegerFieldController.java
@@ -0,0 +1,104 @@
+package dev.isxander.yacl.gui.controllers.string.number;
+
+import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController;
+import net.minecraft.text.Text;
+
+import java.util.function.Function;
+
+/**
+ * {@inheritDoc}
+ */
+public class IntegerFieldController extends NumberFieldController<Integer> {
+ private final int min, max;
+
+ /**
+ * Constructs a double field controller
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ * @param formatter display text, not used whilst editing
+ */
+ public IntegerFieldController(Option<Integer> option, int min, int max, Function<Integer, Text> formatter) {
+ super(option, formatter);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link IntegerSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ */
+ public IntegerFieldController(Option<Integer> option, int min, int max) {
+ this(option, min, max, IntegerSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ * @param formatter display text, not used whilst editing
+ */
+ public IntegerFieldController(Option<Integer> option, Function<Integer, Text> formatter) {
+ this(option, -Integer.MAX_VALUE, Integer.MAX_VALUE, formatter);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link IntegerSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ */
+ public IntegerFieldController(Option<Integer> option) {
+ this(option, -Integer.MAX_VALUE, Integer.MAX_VALUE, IntegerSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double min() {
+ return this.min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double max() {
+ return this.max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getString() {
+ return String.valueOf(option().pendingValue());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPendingValue(double value) {
+ option().requestSet((int) value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double pendingValue() {
+ return option().pendingValue();
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java
new file mode 100644
index 0000000..713d39f
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/LongFieldController.java
@@ -0,0 +1,104 @@
+package dev.isxander.yacl.gui.controllers.string.number;
+
+import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.gui.controllers.slider.LongSliderController;
+import net.minecraft.text.Text;
+
+import java.util.function.Function;
+
+/**
+ * {@inheritDoc}
+ */
+public class LongFieldController extends NumberFieldController<Long> {
+ private final long min, max;
+
+ /**
+ * Constructs a double field controller
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ * @param formatter display text, not used whilst editing
+ */
+ public LongFieldController(Option<Long> option, long min, long max, Function<Long, Text> formatter) {
+ super(option, formatter);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link LongSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ *
+ * @param option option to bind controller to
+ * @param min minimum allowed value (clamped on apply)
+ * @param max maximum allowed value (clamped on apply)
+ */
+ public LongFieldController(Option<Long> option, long min, long max) {
+ this(option, min, max, LongSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ * @param formatter display text, not used whilst editing
+ */
+ public LongFieldController(Option<Long> option, Function<Long, Text> formatter) {
+ this(option, -Long.MAX_VALUE, Long.MAX_VALUE, formatter);
+ }
+
+ /**
+ * Constructs a double field controller.
+ * Uses {@link LongSliderController#DEFAULT_FORMATTER} as display text,
+ * not used whilst editing.
+ * Does not have a minimum or a maximum range.
+ *
+ * @param option option to bind controller to
+ */
+ public LongFieldController(Option<Long> option) {
+ this(option, -Long.MAX_VALUE, Long.MAX_VALUE, LongSliderController.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double min() {
+ return this.min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double max() {
+ return this.max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getString() {
+ return String.valueOf(option().pendingValue());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPendingValue(double value) {
+ option().requestSet((long) value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double pendingValue() {
+ return option().pendingValue();
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java
new file mode 100644
index 0000000..bf0354a
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/NumberFieldController.java
@@ -0,0 +1,69 @@
+package dev.isxander.yacl.gui.controllers.string.number;
+
+import dev.isxander.yacl.api.Option;
+import dev.isxander.yacl.api.utils.Dimension;
+import dev.isxander.yacl.gui.AbstractWidget;
+import dev.isxander.yacl.gui.YACLScreen;
+import dev.isxander.yacl.gui.controllers.slider.ISliderController;
+import dev.isxander.yacl.gui.controllers.string.IStringController;
+import dev.isxander.yacl.gui.controllers.string.StringControllerElement;
+import net.minecraft.text.Text;
+import net.minecraft.util.math.MathHelper;
+
+import java.text.DecimalFormatSymbols;
+import java.util.function.Function;
+
+/**
+ * Controller that allows you to enter in numbers using a text field.
+ *
+ * @param <T> number type
+ */
+public abstract class NumberFieldController<T extends Number> implements ISliderController<T>, IStringController<T> {
+ private final Option<T> option;
+ private final Function<T, Text> displayFormatter;
+
+ public NumberFieldController(Option<T> option, Function<T, Text> displayFormatter) {
+ this.option = option;
+ this.displayFormatter = displayFormatter;
+ }
+
+ @Override
+ public Option<T> option() {
+ return this.option;
+ }
+
+ @Override
+ public void setFromString(String value) {
+ if (value.isEmpty() || value.equals(".") || value.equals("-")) value = "0";
+ setPendingValue(MathHelper.clamp(Double.parseDouble(cleanupNumberString(value)), min(), max()));
+ }
+
+ @Override
+ public double pendingValue() {
+ return option().pendingValue().doubleValue();
+ }
+
+ @Override
+ public boolean isInputValid(String input) {
+ return input.matches("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)|[.]||-");
+ }
+
+ @Override
+ public Text formatValue() {
+ return displayFormatter.apply(option().pendingValue());
+ }
+
+ @Override
+ public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
+ return new StringControllerElement(this, screen, widgetDimension, false);
+ }
+
+ protected String cleanupNumberString(String number) {
+ return number.replace(String.valueOf(DecimalFormatSymbols.getInstance().getGroupingSeparator()), "");
+ }
+
+ @Override
+ public double interval() {
+ return -1;
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java
new file mode 100644
index 0000000..86b9314
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/gui/controllers/string/number/package-info.java
@@ -0,0 +1,10 @@
+/**
+ * This package contains implementations of input fields for different number types
+ * <ul>
+ * <li>For doubles: {@link dev.isxander.yacl.gui.controllers.string.number.DoubleFieldController}</li>
+ * <li>For floats: {@link dev.isxander.yacl.gui.controllers.string.number.FloatFieldController}</li>
+ * <li>For integers: {@link dev.isxander.yacl.gui.controllers.string.number.IntegerFieldController}</li>
+ * <li>For longs: {@link dev.isxander.yacl.gui.controllers.string.number.LongFieldController}</li>
+ * </ul>
+ */
+package dev.isxander.yacl.gui.controllers.string.number;
diff --git a/src/testmod/java/dev/isxander/yacl/test/GuiTest.java b/src/testmod/java/dev/isxander/yacl/test/GuiTest.java
index 7377bc9..492a573 100644
--- a/src/testmod/java/dev/isxander/yacl/test/GuiTest.java
+++ b/src/testmod/java/dev/isxander/yacl/test/GuiTest.java
@@ -9,6 +9,10 @@ import dev.isxander.yacl.gui.controllers.slider.FloatSliderController;
import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController;
import dev.isxander.yacl.gui.controllers.slider.LongSliderController;
import dev.isxander.yacl.gui.controllers.string.StringController;
+import dev.isxander.yacl.gui.controllers.string.number.DoubleFieldController;
+import dev.isxander.yacl.gui.controllers.string.number.FloatFieldController;
+import dev.isxander.yacl.gui.controllers.string.number.IntegerFieldController;
+import dev.isxander.yacl.gui.controllers.string.number.LongFieldController;
import dev.isxander.yacl.test.config.ConfigData;
import dev.isxander.yacl.test.config.Entrypoint;
import net.minecraft.client.MinecraftClient;
@@ -158,6 +162,45 @@ public class GuiTest {
.build())
.build())
.group(OptionGroup.createBuilder()
+ .name(Text.of("Number Fields"))
+ .option(Option.createBuilder(double.class)
+ .name(Text.of("Double Field"))
+ .binding(
+ defaults.doubleField,
+ () -> config.doubleField,
+ value -> config.doubleField = value
+ )
+ .controller(DoubleFieldController::new)
+ .build())
+ .option(Option.createBuilder(float.class)
+ .name(Text.of("Float Field"))
+ .binding(
+ defaults.floatField,
+ () -> config.floatField,
+ value -> config.floatField = value
+ )
+ .controller(FloatFieldController::new)
+ .build())
+ .option(Option.createBuilder(int.class)
+ .name(Text.of("Integer Field"))
+ .binding(
+ defaults.intField,
+ () -> config.intField,
+ value -> config.intField = value
+ )
+ .controller(IntegerFieldController::new)
+ .build())
+ .option(Option.createBuilder(long.class)
+ .name(Text.of("Long Field"))
+ .binding(
+ defaults.longField,
+ () -> config.longField,
+ value -> config.longField = value
+ )
+ .controller(LongFieldController::new)
+ .build())
+ .build())
+ .group(OptionGroup.createBuilder()
.name(Text.of("Enum Controllers"))
.option(Option.createBuilder(ConfigData.Alphabet.class)
.name(Text.of("Enum Cycler"))
diff --git a/src/testmod/java/dev/isxander/yacl/test/config/ConfigData.java b/src/testmod/java/dev/isxander/yacl/test/config/ConfigData.java
index 35e57dd..4eedd9f 100644
--- a/src/testmod/java/dev/isxander/yacl/test/config/ConfigData.java
+++ b/src/testmod/java/dev/isxander/yacl/test/config/ConfigData.java
@@ -14,6 +14,10 @@ public class ConfigData {
@ConfigEntry public long longSlider = 0;
@ConfigEntry public String textField = "Hello";
@ConfigEntry public Color colorOption = Color.red;
+ @ConfigEntry public double doubleField = 0.5;
+ @ConfigEntry public float floatField = 0.5f;
+ @ConfigEntry public int intField = 5;
+ @ConfigEntry public long longField = 5;
@ConfigEntry public Alphabet enumOption = Alphabet.A;
@ConfigEntry public boolean groupTestRoot = false;