diff options
Diffstat (limited to 'src')
9 files changed, 128 insertions, 18 deletions
diff --git a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java index b2bbf95..b6ddcc2 100644 --- a/src/main/java/dev/isxander/yacl/api/ConfigCategory.java +++ b/src/main/java/dev/isxander/yacl/api/ConfigCategory.java @@ -1,10 +1,9 @@ package dev.isxander.yacl.api; import com.google.common.collect.ImmutableList; -import dev.isxander.yacl.gui.YACLScreen; import dev.isxander.yacl.impl.ConfigCategoryImpl; import dev.isxander.yacl.impl.OptionGroupImpl; -import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.NotNull; @@ -31,6 +30,12 @@ public interface ConfigCategory { @NotNull ImmutableList<OptionGroup> groups(); /** + * Tooltip (or description) of the category. + * Rendered on hover. + */ + @NotNull Text tooltip(); + + /** * Creates a builder to construct a {@link ConfigCategory} */ static Builder createBuilder() { @@ -39,10 +44,12 @@ public interface ConfigCategory { class Builder { private Text name; - private final List<Option<?>> rootOptions = new ArrayList<>(); + private final List<Option<?>> rootOptions = new ArrayList<>(); private final List<OptionGroup> groups = new ArrayList<>(); + private final List<Text> tooltipLines = new ArrayList<>(); + private Builder() { } @@ -113,6 +120,20 @@ public interface ConfigCategory { return this; } + /** + * Sets the tooltip to be used by the category. + * 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; + } + public ConfigCategory build() { Validate.notNull(name, "`name` must not be null to build `ConfigCategory`"); Validate.notEmpty(rootOptions, "`at least one option must be added to build `ConfigCategory`"); @@ -121,7 +142,16 @@ public interface ConfigCategory { combinedGroups.add(new OptionGroupImpl(Text.empty(), ImmutableList.copyOf(rootOptions), true)); combinedGroups.addAll(groups); - return new ConfigCategoryImpl(name, ImmutableList.copyOf(combinedGroups)); + MutableText concatenatedTooltip = Text.empty(); + boolean first = true; + for (Text line : tooltipLines) { + if (!first) concatenatedTooltip.append("\n"); + first = false; + + concatenatedTooltip.append(line); + } + + return new ConfigCategoryImpl(name, ImmutableList.copyOf(combinedGroups), concatenatedTooltip); } } } diff --git a/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java b/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java new file mode 100644 index 0000000..f4a50e8 --- /dev/null +++ b/src/main/java/dev/isxander/yacl/gui/CategoryWidget.java @@ -0,0 +1,34 @@ +package dev.isxander.yacl.gui; + +import dev.isxander.yacl.api.ConfigCategory; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.OrderedText; + +import java.util.List; + +public class CategoryWidget extends ButtonWidget { + public float hoveredTicks = 0; + public final List<OrderedText> wrappedDescription; + private int prevMouseX, prevMouseY; + + public CategoryWidget(YACLScreen screen, ConfigCategory category, int x, int y, int width, int height) { + super(x, y, width, height, category.name(), btn -> screen.changeCategory(screen.categoryButtons.indexOf(btn))); + wrappedDescription = MinecraftClient.getInstance().textRenderer.wrapLines(category.tooltip(), screen.width / 2); + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + super.render(matrices, mouseX, mouseY, delta); + + if (isHovered() && prevMouseX == mouseX && prevMouseY == mouseY) { + hoveredTicks += delta; + } else { + hoveredTicks = 0; + } + + prevMouseX = mouseX; + prevMouseY = mouseY; + } +} diff --git a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java index e020065..8cb1160 100644 --- a/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/OptionListWidget.java @@ -31,6 +31,16 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> } @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + for (Entry child : children()) { + if (child.mouseScrolled(mouseX, mouseY, amount)) + return true; + } + + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override protected int getScrollbarPositionX() { return left + super.getScrollbarPositionX(); } @@ -48,12 +58,17 @@ public class OptionListWidget extends ElementListWidget<OptionListWidget.Entry> @Override public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - widget.dim = Dimension.ofInt(x, y, entryWidth, 20); + widget.setDimension(Dimension.ofInt(x, y, entryWidth, 20)); widget.render(matrices, mouseX, mouseY, tickDelta); } @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + return widget.mouseScrolled(mouseX, mouseY, amount); + } + + @Override public List<? extends Selectable> selectableChildren() { return List.of(widget); } diff --git a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java index aab047d..6ecbcc7 100644 --- a/src/main/java/dev/isxander/yacl/gui/YACLScreen.java +++ b/src/main/java/dev/isxander/yacl/gui/YACLScreen.java @@ -21,7 +21,7 @@ public class YACLScreen extends Screen { private final Screen parent; public OptionListWidget optionList; - public final List<ButtonWidget> categoryButtons; + public final List<CategoryWidget> categoryButtons; public ButtonWidget finishedSaveButton, cancelResetButton, undoButton; public YACLScreen(YetAnotherConfigLib config, Screen parent) { @@ -40,11 +40,11 @@ public class YACLScreen extends Screen { Dimension<Integer> categoryDim = Dimension.ofInt(padding, padding, columnWidth - padding * 2, 20); int idx = 0; for (ConfigCategory category : config.categories()) { - ButtonWidget categoryWidget = new ButtonWidget( + CategoryWidget categoryWidget = new CategoryWidget( + this, + category, categoryDim.x(), categoryDim.y(), - categoryDim.width(), categoryDim.height(), - category.name(), - (btn) -> changeCategory(categoryButtons.indexOf(btn)) + categoryDim.width(), categoryDim.height() ); if (idx == currentCategoryIdx) categoryWidget.active = false; @@ -96,6 +96,12 @@ public class YACLScreen extends Screen { super.render(matrices, mouseX, mouseY, delta); optionList.render(matrices, mouseX, mouseY, delta); + + for (CategoryWidget categoryWidget : categoryButtons) { + if (categoryWidget.hoveredTicks > 30) { + renderOrderedTooltip(matrices, categoryWidget.wrappedDescription, mouseX, mouseY); + } + } } @Override @@ -103,7 +109,7 @@ public class YACLScreen extends Screen { updateActionAvailability(); } - private void changeCategory(int idx) { + public void changeCategory(int idx) { int currentIndex = 0; for (ButtonWidget categoryWidget : categoryButtons) { categoryWidget.active = currentIndex != idx; 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 4a14799..9effd26 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/BooleanController.java @@ -42,7 +42,7 @@ public class BooleanController implements Controller<Boolean> { * @param option bound option */ public BooleanController(Option<Boolean> option) { - this(option, ON_OFF_FORMATTER, true); + this(option, ON_OFF_FORMATTER, false); } /** 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 216c945..fe78b2e 100644 --- a/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java +++ b/src/main/java/dev/isxander/yacl/gui/controllers/ControllerWidget.java @@ -16,12 +16,14 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract protected final T control; protected final List<OrderedText> wrappedTooltip; - public Dimension<Integer> dim; + protected Dimension<Integer> dim; protected final Screen screen; protected boolean hovered = false; protected float hoveredTicks = 0; + private int prevMouseX, prevMouseY; + public ControllerWidget(T control, Screen screen, Dimension<Integer> dim) { this.control = control; this.dim = dim; @@ -32,7 +34,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) { + if (hovered && mouseX == prevMouseX && mouseY == prevMouseY) { hoveredTicks += delta; } else { hoveredTicks = 0; @@ -62,9 +64,12 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract drawHoveredControl(matrices, mouseX, mouseY, delta); } - if (hoveredTicks > 40) { + if (hoveredTicks > 30) { screen.renderOrderedTooltip(matrices, wrappedTooltip, mouseX, mouseY); } + + prevMouseX = mouseX; + prevMouseY = mouseY; } protected void drawHoveredControl(MatrixStack matrices, int mouseX, int mouseY, float delta) { @@ -117,6 +122,10 @@ public abstract class ControllerWidget<T extends Controller<?>> extends Abstract return dim.y() + dim.height() / 2f - textRenderer.fontHeight / 2f; } + public void setDimension(Dimension<Integer> dim) { + this.dim = dim; + } + @Override public SelectionType getType() { return hovered ? SelectionType.HOVERED : SelectionType.NONE; 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 5c5e20e..a7dec64 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 @@ -29,8 +29,6 @@ public class SliderControllerElement extends ControllerWidget<ISliderController< public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { super.render(matrices, mouseX, mouseY, delta); - if (sliderBounds == null) - sliderBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - getThumbWidth() / 2 - dim.width() / 3, dim.centerY() - 4, dim.width() / 3, 8); calculateInterpolation(); } @@ -111,6 +109,12 @@ public class SliderControllerElement extends ControllerWidget<ISliderController< interpolation = (float) ((control.pendingValue() - control.min()) * 1 / control.range()); } + @Override + public void setDimension(Dimension<Integer> dim) { + super.setDimension(dim); + sliderBounds = Dimension.ofInt(dim.xLimit() - getXPadding() - getThumbWidth() / 2 - dim.width() / 3, dim.centerY() - 4, dim.width() / 3, 8); + } + private int getThumbX() { return (int) (sliderBounds.x() + sliderBounds.width() * interpolation); } diff --git a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java b/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java index 27bd60c..5a7c9b0 100644 --- a/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java +++ b/src/main/java/dev/isxander/yacl/impl/ConfigCategoryImpl.java @@ -7,6 +7,6 @@ import net.minecraft.text.Text; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public record ConfigCategoryImpl(Text name, ImmutableList<OptionGroup> groups) implements ConfigCategory { +public record ConfigCategoryImpl(Text name, ImmutableList<OptionGroup> groups, Text tooltip) implements ConfigCategory { } diff --git a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java index 0c39ff6..d71a83b 100644 --- a/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java +++ b/src/testmod/java/dev/isxander/yacl/test/ModMenuIntegration.java @@ -22,6 +22,7 @@ public class ModMenuIntegration implements ModMenuApi { .title(Text.of("Test GUI")) .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( @@ -139,6 +140,15 @@ public class ModMenuIntegration implements ModMenuApi { .build()) .category(ConfigCategory.createBuilder() .name(Text.of("Scroll Test")) + .option(Option.createBuilder(int.class) + .name(Text.of("Int Slider that is cut off because the slider")) + .binding( + 0, + () -> TestSettings.scrollingSlider, + (value) -> TestSettings.scrollingSlider = value + ) + .controller(opt -> new IntegerSliderController(opt, 0, 10, 1)) + .build()) .option(ButtonOption.createBuilder() .name(Text.of("Option")) .action(() -> {}) @@ -222,6 +232,8 @@ public class ModMenuIntegration implements ModMenuApi { private static boolean groupTestFirstGroup2 = false; private static boolean groupTestSecondGroup = false; + private static int scrollingSlider = 0; + public enum Alphabet { A, B, C } |