aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/dev/isxander/yacl/api/ConfigCategory.java2
-rw-r--r--src/main/java/dev/isxander/yacl/api/OptionGroup.java32
-rw-r--r--src/main/java/dev/isxander/yacl/gui/CategoryWidget.java3
-rw-r--r--src/main/java/dev/isxander/yacl/gui/OptionListWidget.java60
-rw-r--r--src/main/java/dev/isxander/yacl/gui/YACLScreen.java39
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java20
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java20
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java20
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java35
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java21
-rw-r--r--src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java26
-rw-r--r--src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java4
-rw-r--r--src/main/java/dev/isxander/yacl/impl/OptionImpl.java4
-rw-r--r--src/main/java/dev/isxander/yacl/impl/YACLConstants.java23
-rw-r--r--src/main/resources/assets/yet-another-config-lib/lang/en_us.json3
-rw-r--r--src/main/resources/fabric.mod.json2
-rw-r--r--src/main/resources/icon.pngbin17130 -> 0 bytes
-rw-r--r--src/main/resources/yacl-128x.pngbin0 -> 13813 bytes
-rw-r--r--src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java155
19 files changed, 362 insertions, 107 deletions
diff --git a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java
index 5aafc62..9f2f954 100644
--- a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java
+++ b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java
@@ -138,7 +138,7 @@ public interface ConfigCategory {
Validate.notNull(name, "`name` must not be null to build `ConfigCategory`");
List<OptionGroup> combinedGroups = new ArrayList<>();
- combinedGroups.add(new OptionGroupImpl(Text.empty(), ImmutableList.copyOf(rootOptions), true));
+ combinedGroups.add(new OptionGroupImpl(Text.empty(), Text.empty(), ImmutableList.copyOf(rootOptions), true));
combinedGroups.addAll(groups);
Validate.notEmpty(combinedGroups, "at least one option must be added to build `ConfigCategory`");
diff --git a/src/main/java/dev/isxander/yacl/api/OptionGroup.java b/src/main/java/dev/isxander/yacl/api/OptionGroup.java
index 6a302c4..9376b8e 100644
--- a/src/main/java/dev/isxander/yacl/api/OptionGroup.java
+++ b/src/main/java/dev/isxander/yacl/api/OptionGroup.java
@@ -2,6 +2,7 @@ package dev.isxander.yacl.api;
import com.google.common.collect.ImmutableList;
import dev.isxander.yacl.impl.OptionGroupImpl;
+import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.NotNull;
@@ -23,6 +24,11 @@ public interface OptionGroup {
Text name();
/**
+ * Tooltip displayed on hover.
+ */
+ Text tooltip();
+
+ /**
* List of all options in the group
*/
@NotNull ImmutableList<Option<?>> options();
@@ -42,6 +48,7 @@ public interface OptionGroup {
class Builder {
private Text name = Text.empty();
+ private final List<Text> tooltipLines = new ArrayList<>();
private final List<Option<?>> options = new ArrayList<>();
private Builder() {
@@ -61,6 +68,20 @@ public interface OptionGroup {
}
/**
+ * Sets the tooltip to be used by the option group.
+ * Can be invoked twice to append more lines.
+ * No need to wrap the text yourself, the gui does this itself.
+ *
+ * @param tooltips text lines - merged with a new-line on {@link Builder#build()}.
+ */
+ public Builder tooltip(@NotNull Text... tooltips) {
+ Validate.notEmpty(tooltips, "`tooltips` cannot be empty");
+
+ tooltipLines.addAll(List.of(tooltips));
+ return this;
+ }
+
+ /**
* Adds an option to group.
* To construct an option, use {@link Option#createBuilder(Class)}
*
@@ -89,7 +110,16 @@ public interface OptionGroup {
public OptionGroup build() {
Validate.notEmpty(options, "`options` must not be empty to build `OptionGroup`");
- return new OptionGroupImpl(name, ImmutableList.copyOf(options), false);
+ MutableText concatenatedTooltip = Text.empty();
+ boolean first = true;
+ for (Text line : tooltipLines) {
+ if (!first) concatenatedTooltip.append("\n");
+ first = false;
+
+ concatenatedTooltip.append(line);
+ }
+
+ return new OptionGroupImpl(name, concatenatedTooltip, ImmutableList.copyOf(options), false);
}
}
}
diff --git a/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java b/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java
index f4a50e8..04c4c22 100644
--- a/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java
+++ b/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java
@@ -1,6 +1,7 @@
package dev.isxander.yacl.gui;
import dev.isxander.yacl.api.ConfigCategory;
+import dev.isxander.yacl.impl.YACLConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
@@ -22,7 +23,7 @@ public class CategoryWidget extends ButtonWidget {
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
super.render(matrices, mouseX, mouseY, delta);
- if (isHovered() && prevMouseX == mouseX && prevMouseY == mouseY) {
+ if (isHovered() && (!YACLConstants.HOVER_MOUSE_RESET || (prevMouseX == mouseX && prevMouseY == mouseY))) {
hoveredTicks += delta;
} else {
hoveredTicks = 0;
diff --git a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java
index 8cb1160..1f118cc 100644
--- a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java
+++ b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java
@@ -1,17 +1,24 @@
package dev.isxander.yacl.gui;
+import com.google.common.collect.ImmutableList;
import dev.isxander.yacl.api.ConfigCategory;
import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.OptionGroup;
import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.controllers.ControllerWidget;
+import dev.isxander.yacl.impl.YACLConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
+import net.minecraft.client.gui.screen.narration.NarrationPart;
import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.text.OrderedText;
+import java.util.Collections;
import java.util.List;
public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> {
@@ -23,7 +30,7 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry>
for (OptionGroup group : category.groups()) {
if (!group.isRoot())
- addEntry(new GroupSeparatorEntry(group));
+ addEntry(new GroupSeparatorEntry(group, screen));
for (Option<?> option : group.options()) {
addEntry(new OptionEntry(option.controller().provideWidget(screen, null)));
}
@@ -45,6 +52,13 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry>
return left + super.getScrollbarPositionX();
}
+ @Override
+ protected void renderBackground(MatrixStack matrices) {
+ setRenderBackground(client.world == null);
+ if (client.world != null)
+ fill(matrices, left, top, right, bottom, 0x6B000000);
+ }
+
public static abstract class Entry extends ElementListWidget.Entry<Entry> {
}
@@ -70,36 +84,68 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry>
@Override
public List<? extends Selectable> selectableChildren() {
- return List.of(widget);
+ return ImmutableList.of(widget);
}
@Override
public List<? extends Element> children() {
- return List.of(widget);
+ return ImmutableList.of(widget);
}
}
private static class GroupSeparatorEntry extends Entry {
private final OptionGroup group;
+ private final List<OrderedText> wrappedTooltip;
- public GroupSeparatorEntry(OptionGroup group) {
+ private float hoveredTicks = 0;
+ private int prevMouseX, prevMouseY;
+
+ private final Screen screen;
+ private final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
+
+ public GroupSeparatorEntry(OptionGroup group, Screen screen) {
this.group = group;
+ this.screen = screen;
+ this.wrappedTooltip = textRenderer.wrapLines(group.tooltip(), screen.width / 2);
}
@Override
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
- TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
+ if (hovered && (!YACLConstants.HOVER_MOUSE_RESET || (mouseX == prevMouseX && mouseY == prevMouseY)))
+ hoveredTicks += tickDelta;
+ else
+ hoveredTicks = 0;
+
drawCenteredText(matrices, textRenderer, group.name(), x + entryWidth / 2, y + entryHeight / 2 - textRenderer.fontHeight / 2, -1);
+
+ if (hoveredTicks >= YACLConstants.HOVER_TICKS) {
+ screen.renderOrderedTooltip(matrices, wrappedTooltip, x - 6, y + entryHeight);
+ }
+
+ prevMouseX = mouseX;
+ prevMouseY = mouseY;
}
@Override
public List<? extends Selectable> selectableChildren() {
- return List.of();
+ return ImmutableList.of(new Selectable() {
+ @Override
+ public Selectable.SelectionType getType() {
+ return Selectable.SelectionType.HOVERED;
+ }
+
+ @Override
+ public void appendNarrations(NarrationMessageBuilder builder) {
+ builder.put(NarrationPart.TITLE, group.name());
+ }
+ });
}
@Override
public List<? extends Element> children() {
- return List.of();
+ return Collections.emptyList();
}
+
+
}
}
diff --git a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java
index 6ecbcc7..6da1c29 100644
--- a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java
+++ b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java
@@ -5,10 +5,12 @@ import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.YetAnotherConfigLib;
import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.api.utils.OptionUtils;
+import dev.isxander.yacl.impl.YACLConstants;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
import java.util.ArrayList;
import java.util.List;
@@ -24,6 +26,10 @@ public class YACLScreen extends Screen {
public final List<CategoryWidget> categoryButtons;
public ButtonWidget finishedSaveButton, cancelResetButton, undoButton;
+ public Text saveButtonMessage;
+ private int saveButtonMessageTime;
+
+
public YACLScreen(YetAnotherConfigLib config, Screen parent) {
super(config.title());
this.config = config;
@@ -57,8 +63,16 @@ public class YACLScreen extends Screen {
Dimension<Integer> actionDim = Dimension.ofInt(padding, height - padding - 20, columnWidth - padding * 2, 20);
finishedSaveButton = new ButtonWidget(actionDim.x(), actionDim.y(), actionDim.width(), actionDim.height(), Text.empty(), (btn) -> {
+ saveButtonMessage = null;
+
if (pendingChanges()) {
OptionUtils.forEachOptions(config, Option::applyValue);
+ OptionUtils.forEachOptions(config, option -> {
+ if (option.changed()) {
+ YACLConstants.LOGGER.error("Option '{}' was saved as '{}' but the changes don't seem to have applied.", option.name().getString(), option.pendingValue());
+ setSaveButtonMessage(Text.translatable("yocl.gui.fail_apply").formatted(Formatting.RED));
+ }
+ });
config.saveFunction().run();
} else close();
});
@@ -78,9 +92,9 @@ public class YACLScreen extends Screen {
});
updateActionAvailability();
- addDrawableChild(finishedSaveButton);
addDrawableChild(cancelResetButton);
addDrawableChild(undoButton);
+ addDrawableChild(finishedSaveButton);
ConfigCategory currentCategory = config.categories().get(currentCategoryIdx);
optionList = new OptionListWidget(currentCategory, this, client, width, height);
@@ -98,7 +112,7 @@ public class YACLScreen extends Screen {
optionList.render(matrices, mouseX, mouseY, delta);
for (CategoryWidget categoryWidget : categoryButtons) {
- if (categoryWidget.hoveredTicks > 30) {
+ if (categoryWidget.hoveredTicks > YACLConstants.HOVER_TICKS) {
renderOrderedTooltip(matrices, categoryWidget.wrappedDescription, mouseX, mouseY);
}
}
@@ -107,6 +121,21 @@ public class YACLScreen extends Screen {
@Override
public void tick() {
updateActionAvailability();
+
+ if (saveButtonMessage != null) {
+ if (saveButtonMessageTime > 140) {
+ saveButtonMessage = null;
+ saveButtonMessageTime = 0;
+ } else {
+ saveButtonMessageTime++;
+ finishedSaveButton.setMessage(saveButtonMessage);
+ }
+ }
+ }
+
+ private void setSaveButtonMessage(Text message) {
+ saveButtonMessage = message;
+ saveButtonMessageTime = 0;
}
public void changeCategory(int idx) {
@@ -146,7 +175,11 @@ public class YACLScreen extends Screen {
@Override
public boolean shouldCloseOnEsc() {
- return !undoButton.active;
+ if (pendingChanges()) {
+ setSaveButtonMessage(finishedSaveButton.getMessage().copy().formatted(Formatting.GREEN, Formatting.BOLD));
+ return false;
+ }
+ return true;
}
@Override
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java b/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java
index 92ef3d5..d198c96 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java
@@ -6,6 +6,7 @@ import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.YACLScreen;
import net.minecraft.text.Text;
import org.jetbrains.annotations.ApiStatus;
+import org.lwjgl.glfw.GLFW;
import java.util.function.Consumer;
@@ -71,17 +72,32 @@ public class ActionController implements Controller<Consumer<YACLScreen>> {
super(control, screen, dim);
}
+ public void executeAction() {
+ playDownSound();
+ control.option().action().accept(screen);
+ }
+
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (isMouseOver(mouseX, mouseY)) {
- playDownSound();
- control.option().action().accept(screen);
+ executeAction();
return true;
}
return false;
}
@Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (keyCode != GLFW.GLFW_KEY_ENTER && keyCode != GLFW.GLFW_KEY_SPACE && keyCode != GLFW.GLFW_KEY_KP_ENTER) {
+ return false;
+ }
+
+ executeAction();
+
+ return true;
+ }
+
+ @Override
protected int getHoveredControlWidth() {
return getUnhoveredControlWidth();
}
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java
index 6bf0b80..ac8754f 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java
@@ -9,6 +9,7 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.ApiStatus;
+import org.lwjgl.glfw.GLFW;
import java.util.function.Function;
@@ -117,8 +118,7 @@ public class BooleanController implements Controller<Boolean> {
if (!isMouseOver(mouseX, mouseY))
return false;
- control.option().requestSet(!control.option().pendingValue());
- playDownSound();
+ toggleSetting();
return true;
}
@@ -127,6 +127,11 @@ public class BooleanController implements Controller<Boolean> {
return getUnhoveredControlWidth();
}
+ public void toggleSetting() {
+ control.option().requestSet(!control.option().pendingValue());
+ playDownSound();
+ }
+
@Override
protected Text getValueText() {
if (control.coloured()) {
@@ -135,5 +140,16 @@ public class BooleanController implements Controller<Boolean> {
return super.getValueText();
}
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (keyCode != GLFW.GLFW_KEY_ENTER && keyCode != GLFW.GLFW_KEY_SPACE && keyCode != GLFW.GLFW_KEY_KP_ENTER) {
+ return false;
+ }
+
+ toggleSetting();
+
+ return true;
+ }
}
}
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java
index 77ac9ca..d712e56 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java
@@ -4,6 +4,7 @@ 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 dev.isxander.yacl.impl.YACLConstants;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.util.math.MatrixStack;
@@ -19,6 +20,7 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract
protected Dimension<Integer> dim;
protected final YACLScreen screen;
+ protected boolean focused = false;
protected boolean hovered = false;
protected float hoveredTicks = 0;
@@ -34,7 +36,7 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
hovered = isMouseOver(mouseX, mouseY);
- if (hovered && mouseX == prevMouseX && mouseY == prevMouseY) {
+ if (hovered && (!YACLConstants.HOVER_MOUSE_RESET || (mouseX == prevMouseX && mouseY == prevMouseY))) {
hoveredTicks += delta;
} else {
hoveredTicks = 0;
@@ -53,18 +55,18 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract
Text shortenedName = Text.literal(nameString).fillStyle(name.getStyle());
- drawButtonRect(matrices, dim.x(), dim.y(), dim.xLimit(), dim.yLimit(), hovered);
+ drawButtonRect(matrices, dim.x(), dim.y(), dim.xLimit(), dim.yLimit(), hovered || focused);
matrices.push();
matrices.translate(dim.x() + getXPadding(), getTextY(), 0);
textRenderer.drawWithShadow(matrices, shortenedName, 0, 0, -1);
matrices.pop();
drawValueText(matrices, mouseX, mouseY, delta);
- if (hovered) {
+ if (hovered || focused) {
drawHoveredControl(matrices, mouseX, mouseY, delta);
}
- if (hoveredTicks > 30) {
+ if (hoveredTicks > YACLConstants.HOVER_TICKS) {
screen.renderOrderedTooltip(matrices, wrappedTooltip, mouseX, mouseY);
}
@@ -90,7 +92,7 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract
}
protected int getControlWidth() {
- return hovered ? getHoveredControlWidth() : getUnhoveredControlWidth();
+ return hovered || focused ? getHoveredControlWidth() : getUnhoveredControlWidth();
}
protected abstract int getHoveredControlWidth();
@@ -127,8 +129,14 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract
}
@Override
+ public boolean changeFocus(boolean lookForwards) {
+ this.focused = !this.focused;
+ return this.focused;
+ }
+
+ @Override
public SelectionType getType() {
- return hovered ? SelectionType.HOVERED : SelectionType.NONE;
+ return focused ? SelectionType.FOCUSED : hovered ? SelectionType.HOVERED : SelectionType.NONE;
}
@Override
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java
index f4c4006..af52255 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/EnumController.java
@@ -8,6 +8,7 @@ import dev.isxander.yacl.gui.YACLScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import org.jetbrains.annotations.ApiStatus;
+import org.lwjgl.glfw.GLFW;
import java.util.function.Function;
@@ -85,21 +86,41 @@ public class EnumController<T extends Enum<T>> implements Controller<T> {
this.values = values;
}
+ public void cycleValue(int increment) {
+ int targetIdx = control.option().pendingValue().ordinal() + increment;
+ if (targetIdx >= values.length) {
+ targetIdx -= values.length;
+ } else if (targetIdx < 0) {
+ targetIdx += values.length;
+ }
+ control.option().requestSet(values[targetIdx]);
+ }
+
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (!isMouseOver(mouseX, mouseY) || (button != 0 && button != 1))
return false;
playDownSound();
+ cycleValue(button == 1 || Screen.hasShiftDown() || Screen.hasControlDown() ? -1 : 1);
- int change = button == 1 || Screen.hasShiftDown() ? -1 : 1;
- int targetIdx = control.option().pendingValue().ordinal() + change;
- if (targetIdx >= values.length) {
- targetIdx -= values.length;
- } else if (targetIdx < 0) {
- targetIdx += values.length;
+ return true;
+ }
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ switch (keyCode) {
+ case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN ->
+ cycleValue(-1);
+ case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP ->
+ cycleValue(1);
+ case GLFW.GLFW_KEY_ENTER, GLFW.GLFW_KEY_SPACE, GLFW.GLFW_KEY_KP_ENTER ->
+ cycleValue(Screen.hasControlDown() || Screen.hasShiftDown() ? -1 : 1);
+ default -> {
+ return false;
+ }
}
- control.option().requestSet(values[targetIdx]);
+
return true;
}
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java b/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
index 1d78c78..a1c0095 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/TickBoxController.java
@@ -5,10 +5,10 @@ import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.utils.Dimension;
import dev.isxander.yacl.gui.YACLScreen;
import net.minecraft.client.gui.DrawableHelper;
-import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import org.jetbrains.annotations.ApiStatus;
+import org.lwjgl.glfw.GLFW;
/**
* This controller renders a tickbox
@@ -81,8 +81,7 @@ public class TickBoxController implements Controller<Boolean> {
if (!isMouseOver(mouseX, mouseY))
return false;
- control.option().requestSet(!control.option().pendingValue());
- playDownSound();
+ toggleSetting();
return true;
}
@@ -90,5 +89,21 @@ public class TickBoxController implements Controller<Boolean> {
protected int getHoveredControlWidth() {
return 10;
}
+
+ public void toggleSetting() {
+ control.option().requestSet(!control.option().pendingValue());
+ playDownSound();
+ }
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (keyCode != GLFW.GLFW_KEY_ENTER && keyCode != GLFW.GLFW_KEY_SPACE && keyCode != GLFW.GLFW_KEY_KP_ENTER) {
+ return false;
+ }
+
+ toggleSetting();
+
+ return true;
+ }
}
}
diff --git a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java b/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
index 8af2433..a6f046a 100644
--- a/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
+++ b/src/main/java/dev/isxander/yacl/gui/controllers/slider/SliderControllerElement.java
@@ -8,6 +8,7 @@ import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.ApiStatus;
+import org.lwjgl.glfw.GLFW;
@ApiStatus.Internal
public class SliderControllerElement extends ControllerWidget<ISliderController<?>> {
@@ -49,7 +50,7 @@ public class SliderControllerElement extends ControllerWidget<ISliderController<
@Override
protected void drawValueText(MatrixStack matrices, int mouseX, int mouseY, float delta) {
matrices.push();
- if (hovered)
+ if (hovered || focused)
matrices.translate(-(sliderBounds.width() + 6 + getThumbWidth() / 2f), 0, 0);
super.drawValueText(matrices, mouseX, mouseY, delta);
matrices.pop();
@@ -75,13 +76,17 @@ public class SliderControllerElement extends ControllerWidget<ISliderController<
return true;
}
+ public void incrementValue(double amount) {
+ control.setPendingValue(MathHelper.clamp(control.pendingValue() + interval * amount, min, max));
+ calculateInterpolation();
+ }
+
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
- if (!isMouseOver(mouseX, mouseY) || !Screen.hasShiftDown())
+ if ((!isMouseOver(mouseX, mouseY)) || (!Screen.hasShiftDown() && !Screen.hasControlDown()))
return false;
- control.setPendingValue(MathHelper.clamp(control.pendingValue() + interval * amount, min, max));
- calculateInterpolation();
+ incrementValue(amount);
return true;
}
@@ -95,6 +100,19 @@ public class SliderControllerElement extends ControllerWidget<ISliderController<
}
@Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ switch (keyCode) {
+ case GLFW.GLFW_KEY_LEFT, GLFW.GLFW_KEY_DOWN -> incrementValue(-1);
+ case GLFW.GLFW_KEY_RIGHT, GLFW.GLFW_KEY_UP -> incrementValue(1);
+ default -> {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
public boolean isMouseOver(double mouseX, double mouseY) {
return super.isMouseOver(mouseX, mouseY) || mouseDown;
}
diff --git a/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java
index 73bff07..1f2d4e2 100644
--- a/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java
+++ b/src/main/java/dev/isxander/yacl/impl/OptionGroupImpl.java
@@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableList;
import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.OptionGroup;
import net.minecraft.text.Text;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
-public record OptionGroupImpl(@Nullable Text name, ImmutableList<Option<?>> options, boolean isRoot) implements OptionGroup {
+public record OptionGroupImpl(@NotNull Text name, @NotNull Text tooltip, ImmutableList<Option<?>> options, boolean isRoot) implements OptionGroup {
}
diff --git a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java
index c61eaa1..176bf93 100644
--- a/src/main/java/dev/isxander/yacl/impl/OptionImpl.java
+++ b/src/main/java/dev/isxander/yacl/impl/OptionImpl.java
@@ -69,7 +69,9 @@ public class OptionImpl<T> implements Option<T> {
@Override
public void applyValue() {
- binding().setValue(pendingValue);
+ if (changed()) {
+ binding().setValue(pendingValue);
+ }
}
@Override
diff --git a/src/main/java/dev/isxander/yacl/impl/YACLConstants.java b/src/main/java/dev/isxander/yacl/impl/YACLConstants.java
new file mode 100644
index 0000000..28d6a65
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl/impl/YACLConstants.java
@@ -0,0 +1,23 @@
+package dev.isxander.yacl.impl;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class YACLConstants {
+ /**
+ * Logger used by YACL
+ */
+ @ApiStatus.Internal
+ public static final Logger LOGGER = LoggerFactory.getLogger("YetAnotherConfigLib");
+
+ /**
+ * Amount of ticks to hover before showing tooltips.
+ */
+ public static final int HOVER_TICKS = 20;
+
+ /**
+ * Reset hover ticks back to 0 when the mouse is moved.
+ */
+ public static final boolean HOVER_MOUSE_RESET = true;
+}
diff --git a/src/main/resources/assets/yet-another-config-lib/lang/en_us.json b/src/main/resources/assets/yet-another-config-lib/lang/en_us.json
index 7f609d3..78945de 100644
--- a/src/main/resources/assets/yet-another-config-lib/lang/en_us.json
+++ b/src/main/resources/assets/yet-another-config-lib/lang/en_us.json
@@ -12,5 +12,6 @@
"yacl.gui.finished": "Finished",
"yacl.gui.cancel": "Cancel",
"yacl.gui.reset": "Reset",
- "yacl.gui.undo": "Undo"
+ "yacl.gui.undo": "Undo",
+ "yocl.gui.fail_apply": "Failed to apply"
}
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index 6c28f3c..b40f7eb 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -12,7 +12,7 @@
"issues": "https://github.com/${github}/issues",
"sources": "https://github.com/${github}"
},
- "icon": "icon.png",
+ "icon": "yacl-128x.png",
"license": "LGPL-3.0-or-later",
"environment": "client",
"entrypoints": {
diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png
deleted file mode 100644
index 3f6dae4..0000000
--- a/src/main/resources/icon.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/yacl-128x.png b/src/main/resources/yacl-128x.png
new file mode 100644
index 0000000..c86981c
--- /dev/null
+++ b/src/main/resources/yacl-128x.png
Binary files differ
diff --git a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java
index d1fad67..57d809b 100644
--- a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java
+++ b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java
@@ -27,74 +27,98 @@ public class ModMenuIntegration implements ModMenuApi {
.category(ConfigCategory.createBuilder()
.name(Text.of("Control Examples"))
.tooltip(Text.of("Example Category Description"))
- .option(Option.createBuilder(boolean.class)
- .name(Text.of("Boolean Toggle"))
- .binding(
- false,
- () -> TestSettings.booleanToggle,
- (value) -> TestSettings.booleanToggle = value
- )
- .controller(BooleanController::new)
- .build())
- .option(Option.createBuilder(boolean.class)
- .name(Text.of("Tick Box"))
- .tooltip(Text.of("Super long tooltip that is very descriptive to show off the text wrapping features of the thingy yes whwowwoow"))
- .binding(
- false,
- () -> TestSettings.tickbox,
- (value) -> TestSettings.tickbox = value
- )
- .controller(TickBoxController::new)
- .build())
- .option(Option.createBuilder(int.class)
- .name(Text.of("Int Slider that is cut off because the slider"))
- .binding(
- 0,
- () -> TestSettings.intSlider,
- (value) -> TestSettings.intSlider = value
- )
- .controller(opt -> new IntegerSliderController(opt, 0, 3, 1))
- .build())
- .option(Option.createBuilder(double.class)
- .name(Text.of("Double Slider"))
- .binding(
- 0.0,
- () -> TestSettings.doubleSlider,
- (value) -> TestSettings.doubleSlider = value
- )
- .controller(opt -> new DoubleSliderController(opt, 0, 3, 0.05))
- .build())
- .option(Option.createBuilder(float.class)
- .name(Text.of("Float Slider"))
- .binding(
- 0f,
- () -> TestSettings.floatSlider,
- (value) -> TestSettings.floatSlider = value
- )
- .controller(opt -> new FloatSliderController(opt, 0, 3, 0.1f))
+ .group(OptionGroup.createBuilder()
+ .name(Text.of("Boolean Controllers"))
+ .tooltip(Text.of("Test!"))
+ .option(Option.createBuilder(boolean.class)
+ .name(Text.of("Boolean Toggle"))
+ .tooltip(Text.of("A simple toggle button."))
+ .binding(
+ false,
+ () -> TestSettings.booleanToggle,
+ (value) -> TestSettings.booleanToggle = value
+ )
+ .controller(BooleanController::new)
+ .build())
+ .option(Option.createBuilder(boolean.class)
+ .name(Text.of("Custom Boolean Toggle"))
+ .tooltip(Text.of("You can customize these controllers like this!"))
+ .binding(
+ false,
+ () -> TestSettings.customBooleanToggle,
+ (value) -> TestSettings.customBooleanToggle = value
+ )
+ .controller(opt -> new BooleanController(opt, state -> state ? Text.of("Amazing") : Text.of("Not Amazing"), true))
+ .build())
+ .option(Option.createBuilder(boolean.class)
+ .name(Text.of("Tick Box"))
+ .tooltip(Text.of("There are even alternate methods of displaying the same data type!"))
+ .binding(
+ false,
+ () -> TestSettings.tickbox,
+ (value) -> TestSettings.tickbox = value
+ )
+ .controller(TickBoxController::new)
+ .build())
.build())
- .option(Option.createBuilder(long.class)
- .name(Text.of("Long Slider"))
- .binding(
- 0L,
- () -> TestSettings.longSlider,
- (value) -> TestSettings.longSlider = value
- )
- .controller(opt -> new LongSliderController(opt, 0, 1_000_000, 100))
+ .group(OptionGroup.createBuilder()
+ .name(Text.of("Slider Controllers"))
+ .option(Option.createBuilder(int.class)
+ .name(Text.of("Int Slider that is cut off because the slider"))
+ .binding(
+ 0,
+ () -> TestSettings.intSlider,
+ (value) -> TestSettings.intSlider = value
+ )
+ .controller(opt -> new IntegerSliderController(opt, 0, 3, 1))
+ .build())
+ .option(Option.createBuilder(double.class)
+ .name(Text.of("Double Slider"))
+ .binding(
+ 0.0,
+ () -> TestSettings.doubleSlider,
+ (value) -> TestSettings.doubleSlider = value
+ )
+ .controller(opt -> new DoubleSliderController(opt, 0, 3, 0.05))
+ .build())
+ .option(Option.createBuilder(float.class)
+ .name(Text.of("Float Slider"))
+ .binding(
+ 0f,
+ () -> TestSettings.floatSlider,
+ (value) -> TestSettings.floatSlider = value
+ )
+ .controller(opt -> new FloatSliderController(opt, 0, 3, 0.1f))
+ .build())
+ .option(Option.createBuilder(long.class)
+ .name(Text.of("Long Slider"))
+ .binding(
+ 0L,
+ () -> TestSettings.longSlider,
+ (value) -> TestSettings.longSlider = value
+ )
+ .controller(opt -> new LongSliderController(opt, 0, 1_000_000, 100))
+ .build())
.build())
- .option(Option.createBuilder(TestSettings.Alphabet.class)
- .name(Text.of("Enum Cycler"))
- .binding(
- TestSettings.Alphabet.A,
- () -> TestSettings.enumOption,
- (value) -> TestSettings.enumOption = value
- )
- .controller(opt -> new EnumController<>(opt, TestSettings.Alphabet.class))
+ .group(OptionGroup.createBuilder()
+ .name(Text.of("Enum Controllers"))
+ .option(Option.createBuilder(TestSettings.Alphabet.class)
+ .name(Text.of("Enum Cycler"))
+ .binding(
+ TestSettings.Alphabet.A,
+ () -> TestSettings.enumOption,
+ (value) -> TestSettings.enumOption = value
+ )
+ .controller(opt -> new EnumController<>(opt, TestSettings.Alphabet.class))
+ .build())
.build())
- .option(ButtonOption.createBuilder()
- .name(Text.of("Button \"Option\""))
- .action(screen -> SystemToast.add(MinecraftClient.getInstance().getToastManager(), SystemToast.Type.TUTORIAL_HINT, Text.of("Button Pressed"), Text.of("Button option was invoked!")))
- .controller(ActionController::new)
+ .group(OptionGroup.createBuilder()
+ .name(Text.of("Buttons!"))
+ .option(ButtonOption.createBuilder()
+ .name(Text.of("Button \"Option\""))
+ .action(screen -> SystemToast.add(MinecraftClient.getInstance().getToastManager(), SystemToast.Type.TUTORIAL_HINT, Text.of("Button Pressed"), Text.of("Button option was invoked!")))
+ .controller(ActionController::new)
+ .build())
.build())
.build())
.category(ConfigCategory.createBuilder()
@@ -289,6 +313,7 @@ public class ModMenuIntegration implements ModMenuApi {
private static class TestSettings {
private static boolean booleanToggle = false;
+ private static boolean customBooleanToggle = false;
private static boolean tickbox = false;
private static int intSlider = 0;
private static double doubleSlider = 0;