diff options
author | xander <xander@isxander.dev> | 2022-09-04 22:02:21 +0100 |
---|---|---|
committer | xander <xander@isxander.dev> | 2022-09-04 22:02:21 +0100 |
commit | 833189bb4d8f524c572b6dcc86a7e146cdcf979f (patch) | |
tree | bacf5fdef6b0dbb48b78fe553d5b07f743393670 | |
parent | 9c283303f5b7e7fff820dc2e5c0acdc4719be7a5 (diff) | |
download | YetAnotherConfigLib-833189bb4d8f524c572b6dcc86a7e146cdcf979f.tar.gz YetAnotherConfigLib-833189bb4d8f524c572b6dcc86a7e146cdcf979f.tar.bz2 YetAnotherConfigLib-833189bb4d8f524c572b6dcc86a7e146cdcf979f.zip |
ColorController, javadoc and further improvements to StringController
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java | 198 | ||||
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java | 22 | ||||
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/package-info.java | 1 | ||||
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java | 18 | ||||
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java (renamed from src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java) | 9 | ||||
-rw-r--r-- | src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java | 71 | ||||
-rw-r--r-- | src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java | 11 |
7 files changed, 280 insertions, 50 deletions
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java b/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java new file mode 100644 index 0000000..4d1dfc3 --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java @@ -0,0 +1,198 @@ +package dev.isxander.yacl.gui.controllers; + +import com.google.common.collect.ImmutableList; +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.string.IStringController; +import dev.isxander.yacl.gui.controllers.string.StringControllerElement; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.awt.*; +import java.util.List; + +/** + * A color controller that uses a hex color field as input. + */ +public class ColorController implements IStringController<Color> { + private final Option<Color> option; + private final boolean allowAlpha; + + /** + * Constructs a color controller with {@link ColorController#allowAlpha()} defaulting to false + * + * @param option bound option + */ + public ColorController(Option<Color> option) { + this(option, false); + } + + /** + * Constructs a color controller + * + * @param option bound option + * @param allowAlpha allows the color input to accept alpha values + */ + public ColorController(Option<Color> option, boolean allowAlpha) { + this.option = option; + this.allowAlpha = allowAlpha; + } + + /** + * {@inheritDoc} + */ + @Override + public Option<Color> option() { + return option; + } + + public boolean allowAlpha() { + return allowAlpha; + } + + @Override + public String getString() { + return formatValue().getString(); + } + + @Override + public Text formatValue() { + MutableText text = Text.literal("#"); + if (allowAlpha()) text.append(toHex(option().pendingValue().getAlpha())); + text.append(Text.literal(toHex(option().pendingValue().getRed())).formatted(Formatting.RED)); + text.append(Text.literal(toHex(option().pendingValue().getGreen())).formatted(Formatting.GREEN)); + text.append(Text.literal(toHex(option().pendingValue().getBlue())).formatted(Formatting.BLUE)); + return text; + } + + private String toHex(int value) { + String hex = Integer.toString(value, 16).toUpperCase(); + if (hex.length() == 1) + hex = "0" + hex; + return hex; + } + + @Override + public void setFromString(String value) { + if (value.startsWith("#")) + value = value.substring(1); + + int alpha = Integer.parseInt(value.substring(0, 2), 16); + int red = Integer.parseInt(allowAlpha() ? value.substring(2, 4) : value.substring(0, 2), 16); + int green = Integer.parseInt(allowAlpha() ? value.substring(4, 6) : value.substring(2, 4), 16); + int blue = Integer.parseInt(allowAlpha() ? value.substring(6, 8) : value.substring(4, 6), 16); + + option().requestSet(allowAlpha() ? new Color(red, green, blue, alpha) : new Color(red, green, blue)); + } + + @Override + public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) { + return new ColorControllerElement(this, screen, widgetDimension); + } + + public static class ColorControllerElement extends StringControllerElement { + private final ColorController colorController; + + protected Dimension<Integer> colorPreviewDim; + + private final List<Character> allowedChars; + + public ColorControllerElement(ColorController control, YACLScreen screen, Dimension<Integer> dim) { + super(control, screen, dim); + this.colorController = control; + this.allowedChars = ImmutableList.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + } + + @Override + protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) { + if (isHovered()) { + colorPreviewDim.move(-inputFieldBounds.width() - 5, 0); + super.drawValueText(matrices, mouseX, mouseY, delta); + } + + DrawableHelper.fill(matrices, colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), colorController.option().pendingValue().getRGB()); + drawOutline(matrices, colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), 1, 0xFF000000); + } + + @Override + public void write(String string) { + for (char chr : string.toCharArray()) { + if (!allowedChars.contains(Character.toLowerCase(chr))) { + return; + } + } + + if (caretPos == 0) + return; + + string = string.substring(0, Math.min(inputField.length() - caretPos, string.length())); + + inputField.replace(caretPos, caretPos + string.length(), string); + caretPos += string.length(); + setSelectionLength(); + + updateControl(); + } + + @Override + protected void doBackspace() { + if (caretPos > 1) { + inputField.setCharAt(caretPos - 1, '0'); + caretPos--; + updateControl(); + } + } + + @Override + protected void doDelete() { + + } + + @Override + protected boolean canUseShortcuts() { + return false; + } + + protected void setSelectionLength() { + selectionLength = caretPos < inputField.length() && caretPos > 0 ? 1 : 0; + } + + @Override + protected int getDefaultCarotPos() { + return colorController.allowAlpha() ? 3 : 1; + } + + @Override + public void setDimension(Dimension<Integer> dim) { + super.setDimension(dim); + + int previewSize = (dim.height() - getYPadding() * 2) / 2; + colorPreviewDim = Dimension.ofInt(dim.xLimit() - getXPadding() - previewSize, dim.centerY() - previewSize / 2, previewSize, previewSize); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (super.keyPressed(keyCode, scanCode, modifiers)) { + caretPos = Math.max(1, caretPos); + setSelectionLength(); + return true; + } + return false; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + caretPos = Math.max(1, caretPos); + setSelectionLength(); + return true; + } + return false; + } + } +} diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java b/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java index 63b1b42..f61aedf 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/LabelController.java @@ -9,28 +9,18 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; import org.jetbrains.annotations.ApiStatus; +/** + * Simply renders some text as a label. + */ public class LabelController implements Controller<Text> { private final Option<Text> option; - private final int color; - /** * Constructs a label controller * * @param option bound option */ public LabelController(Option<Text> option) { - this(option, -1); - } - - /** - * Constructs a label controller - * - * @param option bound option - * @param color color of the label - */ - public LabelController(Option<Text> option, int color) { this.option = option; - this.color = color; } /** @@ -41,10 +31,6 @@ public class LabelController implements Controller<Text> { return option; } - public int color() { - return color; - } - @Override public Text formatValue() { return option().pendingValue(); @@ -64,7 +50,7 @@ public class LabelController implements Controller<Text> { @Override public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { - textRenderer.drawWithShadow(matrices, formatValue(), dim.x(), dim.centerY() - textRenderer.fontHeight / 2f, color()); + textRenderer.drawWithShadow(matrices, formatValue(), dim.x(), dim.centerY() - textRenderer.fontHeight / 2f, -1); } } } diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java b/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java index fcfc8e5..88c74c9 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/package-info.java @@ -5,6 +5,7 @@ * <li>For numbers: {@link dev.isxander.yacl.gui.controllers.slider}</li> * <li>For booleans: {@link dev.isxander.yacl.gui.controllers.TickBoxController}</li> * <li>For enums: {@link dev.isxander.yacl.gui.controllers.EnumController}</li> + * <li>For strings: {@link dev.isxander.yacl.gui.controllers.string.StringController}</li> * <li>For {@link dev.isxander.yacl.api.ButtonOption}: {@link dev.isxander.yacl.gui.controllers.ActionController}</li> * </ul> */ diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java index ae66433..41843b8 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/string/IStringController.java @@ -1,12 +1,30 @@ package dev.isxander.yacl.gui.controllers.string; import dev.isxander.yacl.api.Controller; +import dev.isxander.yacl.api.Option; import net.minecraft.text.Text; +/** + * A controller that can be any type but can input and output a string. + */ public interface IStringController<T> extends Controller<T> { + /** + * Gets the option's pending value as a string. + * + * @see Option#pendingValue() + */ String getString(); + + /** + * Sets the option's pending value from a string. + * + * @see Option#requestSet(Object) + */ void setFromString(String value); + /** + * {@inheritDoc} + */ @Override default Text formatValue() { return Text.of(getString()); diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java index edda506..0caaa93 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java @@ -5,15 +5,18 @@ import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.gui.AbstractWidget; import dev.isxander.yacl.gui.YACLScreen; -public class BasicStringController implements IStringController<String> { +/** + * A custom text field implementation for strings. + */ +public class StringController implements IStringController<String> { private final Option<String> option; /** - * Constructs a tickbox controller + * Constructs a string controller * * @param option bound option */ - public BasicStringController(Option<String> option) { + public StringController(Option<String> option) { this.option = option; } diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java index ed066f2..f8cf802 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringControllerElement.java @@ -8,7 +8,6 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.Pair; import org.lwjgl.glfw.GLFW; public class StringControllerElement extends ControllerWidget<IStringController<?>> { @@ -27,7 +26,6 @@ public class StringControllerElement extends ControllerWidget<IStringController< super(control, screen, dim); inputField = new StringBuilder(control.getString()); inputFieldFocused = false; - caretPos = inputField.length(); selectionLength = 0; emptyText = Text.literal("Click to type...").formatted(Formatting.GRAY); } @@ -40,7 +38,7 @@ public class StringControllerElement extends ControllerWidget<IStringController< 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(inputField.substring(0, caretPos)) - 1; + int caretX = inputFieldBounds.x() + textRenderer.getWidth(control.getString().substring(0, caretPos)) - 1; if (inputField.isEmpty()) caretX += inputFieldBounds.width() / 2; @@ -58,18 +56,24 @@ public class StringControllerElement extends ControllerWidget<IStringController< @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (inputFieldBounds.isPointInside((int) mouseX, (int) mouseY)) { - if (!inputFieldFocused) + if (!inputFieldFocused) { inputFieldFocused = true; - else { + caretPos = getDefaultCarotPos(); + } else { int textWidth = (int) mouseX - inputFieldBounds.x(); caretPos = textRenderer.trimToWidth(control.getString(), textWidth).length(); selectionLength = 0; } + return true; } else { inputFieldFocused = false; } - return super.mouseClicked(mouseX, mouseY, button); + return false; + } + + protected int getDefaultCarotPos() { + return inputField.length(); } @Override @@ -115,34 +119,27 @@ public class StringControllerElement extends ControllerWidget<IStringController< return true; } case GLFW.GLFW_KEY_BACKSPACE -> { - if (selectionLength != 0) { - write(""); - } else if (caretPos > 0) { - inputField.deleteCharAt(caretPos - 1); - updateControl(); - caretPos--; - } + doBackspace(); return true; } case GLFW.GLFW_KEY_DELETE -> { - if (caretPos < inputField.length()) { - inputField.deleteCharAt(caretPos); - updateControl(); - } + doDelete(); return true; } } - if (Screen.isPaste(keyCode)) { - this.write(client.keyboard.getClipboard()); - } else if (Screen.isCopy(keyCode) && selectionLength != 0) { - client.keyboard.setClipboard(getSelection()); - } else if (Screen.isCut(keyCode) && selectionLength != 0) { - client.keyboard.setClipboard(getSelection()); - this.write(""); - } else if (Screen.isSelectAll(keyCode)) { - caretPos = inputField.length(); - selectionLength = -caretPos; + if (canUseShortcuts()) { + if (Screen.isPaste(keyCode)) { + this.write(client.keyboard.getClipboard()); + } else if (Screen.isCopy(keyCode) && selectionLength != 0) { + client.keyboard.setClipboard(getSelection()); + } else if (Screen.isCut(keyCode) && selectionLength != 0) { + client.keyboard.setClipboard(getSelection()); + this.write(""); + } else if (Screen.isSelectAll(keyCode)) { + caretPos = inputField.length(); + selectionLength = -caretPos; + } } return false; @@ -158,6 +155,26 @@ public class StringControllerElement extends ControllerWidget<IStringController< return true; } + protected boolean canUseShortcuts() { + return true; + } + + protected void doBackspace() { + if (selectionLength != 0) { + write(""); + } else if (caretPos > 0) { + inputField.deleteCharAt(caretPos - 1); + caretPos--; + } + } + + protected void doDelete() { + if (caretPos < inputField.length()) { + inputField.deleteCharAt(caretPos); + updateControl(); + } + } + public void write(String string) { if (selectionLength == 0) { string = textRenderer.trimToWidth(string, getMaxLength() - textRenderer.getWidth(inputField.toString())); diff --git a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java index b966ae8..f90beb8 100644 --- a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java +++ b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java @@ -8,13 +8,15 @@ import dev.isxander.yacl.gui.controllers.slider.DoubleSliderController; 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.BasicStringController; +import dev.isxander.yacl.gui.controllers.string.StringController; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.option.GraphicsMode; import net.minecraft.client.toast.SystemToast; import net.minecraft.text.Text; +import java.awt.*; + public class ModMenuIntegration implements ModMenuApi { @Override public ConfigScreenFactory<?> getModConfigScreenFactory() { @@ -130,7 +132,12 @@ public class ModMenuIntegration implements ModMenuApi { () -> TestSettings.textField, value -> TestSettings.textField = value ) - .controller(BasicStringController::new) + .controller(StringController::new) + .build()) + .option(Option.createBuilder(Color.class) + .name(Text.of("Color Option")) + .binding(Binding.immutable(Color.red)) + .controller(ColorController::new) .build()) .build()) .group(OptionGroup.createBuilder() |