From 833189bb4d8f524c572b6dcc86a7e146cdcf979f Mon Sep 17 00:00:00 2001 From: xander Date: Sun, 4 Sep 2022 22:02:21 +0100 Subject: ColorController, javadoc and further improvements to StringController --- .../yacl/gui/controllers/ColorController.java | 198 +++++++++++++++++++++ .../yacl/gui/controllers/LabelController.java | 22 +-- .../yacl/gui/controllers/package-info.java | 1 + .../controllers/string/BasicStringController.java | 42 ----- .../gui/controllers/string/IStringController.java | 18 ++ .../gui/controllers/string/StringController.java | 45 +++++ .../string/StringControllerElement.java | 71 +++++--- 7 files changed, 310 insertions(+), 87 deletions(-) create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/ColorController.java delete mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java create mode 100644 src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java (limited to 'src/main/java/dev/isxander') 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 { + private final Option option; + private final boolean allowAlpha; + + /** + * Constructs a color controller with {@link ColorController#allowAlpha()} defaulting to false + * + * @param option bound option + */ + public ColorController(Option 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 option, boolean allowAlpha) { + this.option = option; + this.allowAlpha = allowAlpha; + } + + /** + * {@inheritDoc} + */ + @Override + public Option 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 widgetDimension) { + return new ColorControllerElement(this, screen, widgetDimension); + } + + public static class ColorControllerElement extends StringControllerElement { + private final ColorController colorController; + + protected Dimension colorPreviewDim; + + private final List allowedChars; + + public ColorControllerElement(ColorController control, YACLScreen screen, Dimension 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 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 { private final Option option; - private final int color; - /** * Constructs a label controller * * @param option bound option */ public LabelController(Option option) { - this(option, -1); - } - - /** - * Constructs a label controller - * - * @param option bound option - * @param color color of the label - */ - public LabelController(Option option, int color) { this.option = option; - this.color = color; } /** @@ -41,10 +31,6 @@ public class LabelController implements Controller { return option; } - public int color() { - return color; - } - @Override public Text formatValue() { return option().pendingValue(); @@ -64,7 +50,7 @@ public class LabelController implements Controller { @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 @@ *
  • For numbers: {@link dev.isxander.yacl.gui.controllers.slider}
  • *
  • For booleans: {@link dev.isxander.yacl.gui.controllers.TickBoxController}
  • *
  • For enums: {@link dev.isxander.yacl.gui.controllers.EnumController}
  • + *
  • For strings: {@link dev.isxander.yacl.gui.controllers.string.StringController}
  • *
  • For {@link dev.isxander.yacl.api.ButtonOption}: {@link dev.isxander.yacl.gui.controllers.ActionController}
  • * */ diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java deleted file mode 100644 index edda506..0000000 --- a/src/main/java/dev/isxander/yacl/gui/controllers/string/BasicStringController.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.isxander.yacl.gui.controllers.string; - -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; - -public class BasicStringController implements IStringController { - private final Option option; - - /** - * Constructs a tickbox controller - * - * @param option bound option - */ - public BasicStringController(Option option) { - this.option = option; - } - - /** - * {@inheritDoc} - */ - @Override - public Option option() { - return option; - } - - @Override - public String getString() { - return option().pendingValue(); - } - - @Override - public void setFromString(String value) { - option().requestSet(value); - } - - @Override - public AbstractWidget provideWidget(YACLScreen screen, Dimension widgetDimension) { - return new StringControllerElement(this, screen, widgetDimension); - } -} 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 extends Controller { + /** + * 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/StringController.java b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java new file mode 100644 index 0000000..0caaa93 --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/controllers/string/StringController.java @@ -0,0 +1,45 @@ +package dev.isxander.yacl.gui.controllers.string; + +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; + +/** + * A custom text field implementation for strings. + */ +public class StringController implements IStringController { + private final Option option; + + /** + * Constructs a string controller + * + * @param option bound option + */ + public StringController(Option option) { + this.option = option; + } + + /** + * {@inheritDoc} + */ + @Override + public Option option() { + return option; + } + + @Override + public String getString() { + return option().pendingValue(); + } + + @Override + public void setFromString(String value) { + option().requestSet(value); + } + + @Override + public AbstractWidget provideWidget(YACLScreen screen, Dimension widgetDimension) { + return new StringControllerElement(this, screen, widgetDimension); + } +} 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> { @@ -27,7 +26,6 @@ public class StringControllerElement extends ControllerWidget { - 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 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())); -- cgit