aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/dev/isxander/yacl3/gui/controllers
diff options
context:
space:
mode:
authorisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
committerisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
commit04fe933f4c24817100f3101f088accf55a621f8a (patch)
treefeff94ca3ab4484160e69a24f4ee38522381950e /src/main/java/dev/isxander/yacl3/gui/controllers
parent831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff)
downloadYetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.gz
YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.bz2
YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.zip
Extremely fragile and broken multiversion build with stonecutter
Diffstat (limited to 'src/main/java/dev/isxander/yacl3/gui/controllers')
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/ActionController.java120
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/BooleanController.java164
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/ColorController.java220
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/ControllerWidget.java148
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/LabelController.java193
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/ListEntryWidget.java128
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/TickBoxController.java119
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingControllerElement.java60
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/cycling/CyclingListController.java86
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/cycling/EnumController.java48
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/cycling/ICyclingController.java38
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownController.java87
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/AbstractDropdownControllerElement.java248
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/DropdownStringController.java34
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/DropdownStringControllerElement.java31
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownController.java92
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/EnumDropdownControllerElement.java25
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/ItemController.java68
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/dropdown/ItemControllerElement.java87
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/package-info.java12
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/DoubleSliderController.java119
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/FloatSliderController.java119
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/ISliderController.java54
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/IntegerSliderController.java116
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/LongSliderController.java116
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/SliderControllerElement.java157
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/slider/package-info.java10
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/IStringController.java44
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/StringController.java37
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java466
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/DoubleFieldController.java111
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/FloatFieldController.java111
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/IntegerFieldController.java111
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/LongFieldController.java111
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/NumberFieldController.java80
-rw-r--r--src/main/java/dev/isxander/yacl3/gui/controllers/string/number/package-info.java10
36 files changed, 3780 insertions, 0 deletions
diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/ActionController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/ActionController.java
new file mode 100644
index 0000000..77938f6
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/gui/controllers/ActionController.java
@@ -0,0 +1,120 @@
+package dev.isxander.yacl3.gui.controllers;
+
+import com.mojang.blaze3d.platform.InputConstants;
+import dev.isxander.yacl3.api.ButtonOption;
+import dev.isxander.yacl3.api.Controller;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import net.minecraft.network.chat.Component;
+
+import java.util.function.BiConsumer;
+
+/**
+ * Simple controller that simply runs the button action on press
+ * and renders a {@link} Text on the right.
+ */
+public class ActionController implements Controller<BiConsumer<YACLScreen, ButtonOption>> {
+ public static final Component DEFAULT_TEXT = Component.translatable("yacl.control.action.execute");
+
+ private final ButtonOption option;
+ private final Component text;
+
+ /**
+ * Constructs an action controller
+ * with the default formatter of {@link ActionController#DEFAULT_TEXT}
+ *
+ * @param option bound option
+ */
+ public ActionController(ButtonOption option) {
+ this(option, DEFAULT_TEXT);
+ }
+
+ /**
+ * Constructs an action controller
+ *
+ * @param option bound option
+ * @param text text to display
+ */
+ public ActionController(ButtonOption option, Component text) {
+ this.option = option;
+ this.text = text;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ButtonOption option() {
+ return option;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Component formatValue() {
+ return text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
+ return new ActionControllerElement(this, screen, widgetDimension);
+ }
+
+ public static class ActionControllerElement extends ControllerWidget<ActionController> {
+ private final String buttonString;
+
+ public ActionControllerElement(ActionController control, YACLScreen screen, Dimension<Integer> dim) {
+ super(control, screen, dim);
+ buttonString = control.formatValue().getString().toLowerCase();
+ }
+
+ public void executeAction() {
+ playDownSound();
+ control.option().action().accept(screen, control.option());
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (isMouseOver(mouseX, mouseY) && isAvailable()) {
+ executeAction();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (!focused) {
+ return false;
+ }
+
+ if (keyCode == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_SPACE || keyCode == InputConstants.KEY_NUMPADENTER) {
+ executeAction();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected int getHoveredControlWidth() {
+ return getUnhoveredControlWidth();
+ }
+
+ @Override
+ public boolean canReset() {
+ return false;
+ }
+
+ @Override
+ public boolean matchesSearch(String query) {
+ return super.matchesSearch(query) || buttonString.contains(query);
+ }
+ }
+}
diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/BooleanController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/BooleanController.java
new file mode 100644
index 0000000..cbd6ba5
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/gui/controllers/BooleanController.java
@@ -0,0 +1,164 @@
+package dev.isxander.yacl3.gui.controllers;
+
+import com.mojang.blaze3d.platform.InputConstants;
+import dev.isxander.yacl3.api.Controller;
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.controller.ValueFormatter;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.network.chat.CommonComponents;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.function.Function;
+
+/**
+ * This controller renders a simple formatted {@link Component}
+ */
+public class BooleanController implements Controller<Boolean> {
+
+ public static final Function<Boolean, Component> ON_OFF_FORMATTER = (state) ->
+ state
+ ? CommonComponents.OPTION_ON
+ : CommonComponents.OPTION_OFF;
+
+ public static final Function<Boolean, Component> TRUE_FALSE_FORMATTER = (state) ->
+ state
+ ? Component.translatable("yacl.control.boolean.true")
+ : Component.translatable("yacl.control.boolean.false");
+
+ public static final Function<Boolean, Component> YES_NO_FORMATTER = (state) ->
+ state
+ ? CommonComponents.GUI_YES
+ : CommonComponents.GUI_NO;
+
+ private final Option<Boolean> option;
+ private final ValueFormatter<Boolean> valueFormatter;
+ private final boolean coloured;
+
+ /**
+ * Constructs a tickbox controller
+ * with the default value formatter of {@link BooleanController#ON_OFF_FORMATTER}
+ *
+ * @param option bound option
+ */
+ public BooleanController(Option<Boolean> option) {
+ this(option, ON_OFF_FORMATTER, false);
+ }
+
+ /**
+ * Constructs a tickbox controller
+ * with the default value formatter of {@link BooleanController#ON_OFF_FORMATTER}
+ *
+ * @param option bound option
+ * @param coloured value format is green or red depending on the state
+ */
+ public BooleanController(Option<Boolean> option, boolean coloured) {
+ this(option, ON_OFF_FORMATTER, coloured);
+ }
+
+ /**
+ * Constructs a tickbox controller
+ *
+ * @param option bound option
+ * @param valueFormatter format value into any {@link Component}
+ * @param coloured value format is green or red depending on the state
+ */
+ public BooleanController(Option<Boolean> option, Function<Boolean, Component> valueFormatter, boolean coloured) {
+ this.option = option;
+ this.valueFormatter = valueFormatter::apply;
+ this.coloured = coloured;
+ }
+
+ @ApiStatus.Internal
+ public static BooleanController createInternal(Option<Boolean> option, ValueFormatter<Boolean> formatter, boolean coloured) {
+ return new BooleanController(option, formatter::format, coloured);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Boolean> option() {
+ return option;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Component formatValue() {
+ return valueFormatter.format(option().pendingValue());
+ }
+
+ /**
+ * Value format is green or red depending on the state
+ */
+ public boolean coloured() {
+ return coloured;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AbstractWidget provideWidget(YACLScreen screen, Dimension<Integer> widgetDimension) {
+ return new BooleanControllerElement(this, screen, widgetDimension);
+ }
+
+ public static class BooleanControllerElement extends ControllerWidget<BooleanController> {
+ public BooleanControllerElement(BooleanController control, YACLScreen screen, Dimension<Integer> dim) {
+ super(control, screen, dim);
+ }
+
+ @Override
+ protected void drawHoveredControl(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (!isMouseOver(mouseX, mouseY) || !isAvailable())
+ return false;
+
+ toggleSetting();
+ return true;
+ }
+
+ @Override
+ protected int getHoveredControlWidth() {
+ return getUnhoveredControlWidth();
+ }
+
+ public void toggleSetting() {
+ control.option().requestSet(!control.option().pendingValue());
+ playDownSound();
+ }
+
+ @Override
+ protected Component getValueText() {
+ if (control.coloured()) {
+ return super.getValueText().copy().withStyle(control.option().pendingValue() ? ChatFormatting.GREEN : ChatFormatting.RED);
+ }
+
+ return super.getValueText();
+ }
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (!isFocused()) {
+ return false;
+ }
+
+ if (keyCode == InputConstants.KEY_RETURN || keyCode == InputConstants.KEY_SPACE || keyCode == InputConstants.KEY_NUMPADENTER) {
+ toggleSetting();
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/ColorController.java b/src/main/java/dev/isxander/yacl3/gui/controllers/ColorController.java
new file mode 100644
index 0000000..56e6d30
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/gui/controllers/ColorController.java
@@ -0,0 +1,220 @@
+package dev.isxander.yacl3.gui.controllers;
+
+import com.google.common.collect.ImmutableList;
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.api.utils.MutableDimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import dev.isxander.yacl3.gui.controllers.string.IStringController;
+import dev.isxander.yacl3.gui.controllers.string.StringControllerElement;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+
+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 Component formatValue() {
+ MutableComponent text = Component.literal("#");
+ text.append(Component.literal(toHex(option().pendingValue().getRed())).withStyle(ChatFormatting.RED));
+ text.append(Component.literal(toHex(option().pendingValue().getGreen())).withStyle(ChatFormatting.GREEN));
+ text.append(Component.literal(toHex(option().pendingValue().getBlue())).withStyle(ChatFormatting.BLUE));
+ if (allowAlpha()) text.append(toHex(option().pendingValue().getAlpha()));
+ 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 red = Integer.parseInt(value.substring(0, 2), 16);
+ int green = Integer.parseInt(value.substring(2, 4), 16);
+ int blue = Integer.parseInt(value.substring(4, 6), 16);
+
+ if (allowAlpha()) {
+ int alpha = Integer.parseInt(value.substring(6, 8), 16);
+ option().requestSet(new Color(red, green, blue, alpha));
+ } else {
+ option().requestSet(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 MutableDimension<Integer> colorPreviewDim;
+
+ private final List<Character> allowedChars;
+
+ public ColorControllerElement(ColorController control, YACLScreen screen, Dimension<Integer> 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');
+ }
+
+ @Override
+ protected void drawValueText(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ if (isHovered()) {
+ colorPreviewDim.move(-inputFieldBounds.width() - 5, 0);
+ super.drawValueText(graphics, mouseX, mouseY, delta);
+ }
+
+ graphics.fill(colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), colorController.option().pendingValue().getRGB());
+ drawOutline(graphics, colorPreviewDim.x(), colorPreviewDim.y(), colorPreviewDim.xLimit(), colorPreviewDim.yLimit(), 1, 0xFF000000);
+ }
+
+ @Override
+ public void write(String string) {
+ if (string.startsWith("0x")) string = string.substring(2);
+ for (char chr : string.toCharArray()) {
+ if (!allowedChars.contains(Character.toLowerCase(chr))) {
+ return;
+ }
+ }
+
+ if (caretPos == 0)
+ return;
+
+ String trimmed = string.substring(0, Math.min(inputField.length() - caretPos, string.length()));
+
+ if (modifyInput(builder -> builder.replace(caretPos, caretPos + trimmed.length(), trimmed))) {
+ caretPos += trimmed.length();
+ setSelectionLength();
+ updateControl();
+ }
+ }
+
+ @Override
+ protected void doBackspace() {
+ if (caretPos > 1) {
+ if (modifyInput(builder -> builder.setCharAt(caretPos - 1, '0'))) {
+ caretPos--;
+ updateControl();
+ }
+ }
+ }
+
+ @Override
+ protected void doDelete() {
+ if (caretPos >= 1) {
+ if (modifyInput(builder -> builder.setCharAt(caretPos, '0'))) {
+ updateControl();
+ }
+ }
+ }
+
+ @Override
+ protected boolean doCut() {
+ return false;
+ }
+
+ @Override
+ protected boolean doCopy() {
+ return false;
+ }
+
+ @Override
+ protected boolean doSelectAll() {
+ return false;
+ }
+
+ protected void setSelectionLength() {
+ selectionLength = caretPos < inputField.length() && caretPos > 0 ? 1 : 0;
+ }
+
+ @Override
+ protected int getDefaultCaretPos() {
+ 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) {
+ int prevSelectionLength = selectionLength;
+ selectionLength = 0;
+ if (super.keyPressed(keyCode, scanCode, modifiers)) {
+ caretPos = Math.max(1, caretPos);
+ setSelectionLength();
+ return true;
+ } else selectionLength = prevSelectionLength;
+ 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/yacl3/gui/controllers/ControllerWidget.java b/src/main/java/dev/isxander/yacl3/gui/controllers/ControllerWidget.java
new file mode 100644
index 0000000..19fe2f6
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/gui/controllers/ControllerWidget.java
@@ -0,0 +1,148 @@
+package dev.isxander.yacl3.gui.controllers;
+
+import dev.isxander.yacl3.api.Controller;
+import dev.isxander.yacl3.api.utils.Dimension;
+import dev.isxander.yacl3.gui.AbstractWidget;
+import dev.isxander.yacl3.gui.YACLScreen;
+import dev.isxander.yacl3.gui.utils.GuiUtils;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.gui.ComponentPath;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.components.MultiLineLabel;
+import net.minecraft.client.gui.narration.NarratedElementType;
+import net.minecraft.client.gui.narration.NarrationElementOutput;
+import net.minecraft.client.gui.navigation.FocusNavigationEvent;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class ControllerWidget<T extends Controller<?>> extends AbstractWidget {
+ protected final T control;
+ protected MultiLineLabel wrappedTooltip;
+ protected final YACLScreen screen;
+
+ protected boolean focused = false;
+ protected boolean hovered = false;
+
+ protected final Component modifiedOptionName;
+ protected final String optionNameString;
+
+ public ControllerWidget(T control, YACLScreen screen, Dimension<Integer> dim) {
+ super(dim);
+ this.control = control;
+ this.screen = screen;
+ control.option().addListener((opt, pending) -> updateTooltip());
+ updateTooltip();
+ this.modifiedOptionName = control.option().name().copy().withStyle(ChatFormatting.ITALIC);
+ this.optionNameString = control.option().name().getString().toLowerCase();
+ }
+
+ @Override
+ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ hovered = isMouseOver(mouseX, mouseY);
+
+ Component name = control.option().changed() ? modifiedOptionName : control.option().name();
+ Component shortenedName = Component.literal(GuiUtils.shortenString(name.getString(), textRenderer, getDimension().width() - getControlWidth() - getXPadding() - 7, "...")).setStyle(name.getStyle());
+
+ drawButtonRect(graphics, getDimension().x(), getDimension().y(), getDimension().xLimit(), getDimension().yLimit(), hovered || focused, isAvailable());
+ graphics.drawString(textRenderer, shortenedName, getDimension().x() + getXPadding(), getTextY(), getValueColor(), true);
+
+
+ drawValueText(graphics, mouseX, mouseY, delta);
+ if (isHovered()) {
+ drawHoveredControl(graphics, mouseX, mouseY, delta);
+ }
+ }
+
+ protected void drawHoveredControl(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+
+ }
+
+ protected void drawValueText(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ Component valueText = getValueText();
+ graphics.drawString(textRenderer, valueText, getDimension().xLimit() - textRenderer.width(valueText) - getXPadding(), getTextY(), getValueColor(), true);
+ }
+
+ private void updateTooltip() {
+ this.wrappedTooltip = MultiLineLabel.create(textRenderer, control.option().tooltip(), screen.width / 3 * 2 - 10);
+ }
+
+ protected int getControlWidth() {
+ return isHovered() ? getHoveredControlWidth() : getUnhoveredControlWidth();
+ }
+
+ public boolean isHovered() {
+ return isAvailable() && (hovered || focused);
+ }
+
+ protected abstract int getHoveredControlWidth();
+
+ protected int getUnhoveredControlWidth() {
+ return textRenderer.width(getValueText());
+ }
+
+ protected int getXPadding() {
+ return 5;
+ }
+
+ protected int getYPadding() {
+ return 2;
+ }
+
+ protected Component getValueText() {
+ return control.formatValue();
+ }
+
+ protected boolean isAvailable() {
+ return control.option().available();
+ }
+
+ protected int getValueColor() {
+ return isAvailable() ? -1 : inactiveColor;
+ }
+
+ @Override
+ public boolean canReset() {
+ return true;
+ }
+
+ protected int getTextY() {
+ return (int)(getDimension().y() + getDimension().height() / 2f - textRenderer.lineHeight / 2f);
+ }
+
+ @Nullable
+ @Override
+ public ComponentPath nextFocusPath(FocusNavigationEvent focusNavigationEvent) {
+ return !this.isFocused() ? ComponentPath.leaf(this) : null;
+ }
+
+ @Override
+ public boolean isFocused() {
+ return focused;
+ }
+
+ @Override
+ public void setFocused(boolean focused) {
+ this.focused = focused;
+ }
+
+ @Override
+ public void unfocus() {
+ this.focused = false;
+ }
+
+ @Override
+ public boolean matche