diff --git a/common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java b/common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java index c5214817..2876674d 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/ClothConfigDemo.java @@ -23,8 +23,7 @@ import com.mojang.blaze3d.platform.InputConstants; import me.shedaniel.autoconfig.util.Utils; import me.shedaniel.clothconfig2.api.*; -import me.shedaniel.clothconfig2.gui.entries.MultiElementListEntry; -import me.shedaniel.clothconfig2.gui.entries.NestedListListEntry; +import me.shedaniel.clothconfig2.gui.entries.*; import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder; import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder; import net.minecraft.ChatFormatting; @@ -79,6 +78,10 @@ public int hashCode() { return result; } } + + enum DependencyDemoEnum { + EXCELLENT, GOOD, OKAY, BAD, HORRIBLE + } ConfigBuilder builder = ConfigBuilder.create().setTitle(Component.translatable("title.cloth-config.config")); builder.setDefaultBackgroundTexture(new ResourceLocation("minecraft:textures/block/oak_planks.png")); @@ -154,6 +157,51 @@ public int hashCode() { } } )); + + SubCategoryBuilder depends = entryBuilder.startSubCategory(Component.literal("Dependencies")).setExpanded(true); + BooleanListEntry dependency = entryBuilder.startBooleanToggle(Component.literal("A cool toggle"), false).setTooltip(Component.literal("Toggle me...")).build(); + depends.add(dependency); + Collection toggles = new LinkedList<>(); + toggles.add(entryBuilder.startBooleanToggle(Component.literal("I only work when cool is toggled..."), true) + .setRequirement(Requirement.isTrue(dependency)).build()); + toggles.add(entryBuilder.startBooleanToggle(Component.literal("I only appear when cool is toggled..."), true) + .setDisplayRequirement(Requirement.isTrue(dependency)).build()); + depends.addAll(toggles); + depends.add(entryBuilder.startBooleanToggle(Component.literal("I only work when cool matches both of these toggles ^^"), true) + .setRequirement(Requirement.all( + toggles.stream() + .map(toggle -> Requirement.matches(dependency, toggle)) + .toArray(Requirement[]::new))) + .build()); + SubCategoryBuilder dependantSub = entryBuilder.startSubCategory(Component.literal("Sub-categories can have requirements too...")) + .setRequirement(Requirement.isTrue(dependency)); + dependantSub.add(entryBuilder.startTextDescription(Component.literal("This sub category depends on Cool being toggled")).build()); + dependantSub.add(entryBuilder.startBooleanToggle(Component.literal("Example entry"), true).build()); + dependantSub.add(entryBuilder.startBooleanToggle(Component.literal("Another example..."), true).build()); + depends.add(dependantSub.build()); + depends.add(entryBuilder.startLongList(Component.literal("Even lists!"), Arrays.asList(1L, 2L, 3L)).setDefaultValue(Arrays.asList(1L, 2L, 3L)) + .setRequirement(Requirement.isTrue(dependency)).build()); + EnumListEntry enumDependency = entryBuilder.startEnumSelector(Component.literal("Select a good or bad option"), DependencyDemoEnum.class, DependencyDemoEnum.OKAY).build(); + depends.add(enumDependency); + IntegerSliderEntry intDependency = entryBuilder.startIntSlider(Component.literal("Select something big or small"), 50, -100, 100).build(); + depends.add(intDependency); + depends.add(entryBuilder.startBooleanToggle(Component.literal("I only work when a good option is chosen..."), true).setTooltip(Component.literal("Select good or better above")) + .setRequirement(Requirement.isValue(enumDependency, DependencyDemoEnum.EXCELLENT, DependencyDemoEnum.GOOD)) + .build()); + depends.add(entryBuilder.startBooleanToggle(Component.literal("I need a good option AND a cool toggle!"), true).setTooltip(Component.literal("Select good or better and also toggle cool")) + .setRequirement(Requirement.all( + Requirement.isTrue(dependency), + Requirement.isValue(enumDependency, DependencyDemoEnum.EXCELLENT, DependencyDemoEnum.GOOD))) + .build()); + depends.add(entryBuilder.startBooleanToggle(Component.literal("I only work when numbers are extreme!"), true) + .setTooltip(Component.literal("Move the slider...")) + .setRequirement(Requirement.any( + () -> intDependency.getValue() < -70, + () -> intDependency.getValue() > 70)) + .build()); + + testing.addEntry(depends.build()); + testing.addEntry(entryBuilder.startTextDescription( Component.translatable("text.cloth-config.testing.1", Component.literal("ClothConfig").withStyle(s -> s.withBold(true).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(Util.make(new ItemStack(Items.PINK_WOOL), stack -> stack.setHoverName(Component.literal("(\u30FB\u2200\u30FB)")).enchant(Enchantments.BLOCK_EFFICIENCY, 10)))))), diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java index 619eed92..693893fc 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigEntry.java @@ -29,21 +29,21 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; @Environment(EnvType.CLIENT) -public abstract class AbstractConfigEntry extends DynamicElementListWidget.ElementEntry> implements ReferenceProvider { +public abstract class AbstractConfigEntry extends DynamicElementListWidget.ElementEntry> implements ReferenceProvider, ValueHolder { private AbstractConfigScreen screen; private Supplier> errorSupplier; @Nullable @@ -92,6 +92,8 @@ public Component getDisplayedFieldName() { text = text.withStyle(ChatFormatting.ITALIC); if (!hasError && !isEdited) text = text.withStyle(ChatFormatting.GRAY); + if (!isEnabled()) + text = text.withStyle(ChatFormatting.DARK_GRAY); return text; } @@ -117,8 +119,6 @@ public void appendSearchTags(Iterable tags) { } } - public abstract T getValue(); - public final Optional getConfigError() { if (errorSupplier != null && errorSupplier.get().isPresent()) return errorSupplier.get(); @@ -146,6 +146,19 @@ public final void addTooltip(@NotNull Tooltip tooltip) { screen.addTooltip(tooltip); } + protected FormattedCharSequence[] wrapLinesToScreen(Component[] lines) { + return wrapLines(lines, screen.width); + } + + protected FormattedCharSequence[] wrapLines(Component[] lines, int width) { + final Font font = Minecraft.getInstance().font; + + return Arrays.stream(lines) + .map(line -> font.split(line, width)) + .flatMap(List::stream) + .toArray(FormattedCharSequence[]::new); + } + public void updateSelected(boolean isSelected) {} @ApiStatus.Internal diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java index 2352b371..4906157f 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/AbstractConfigListEntry.java @@ -48,7 +48,7 @@ public void setRequiresRestart(boolean requiresRestart) { } public boolean isEditable() { - return getConfigScreen().isEditable() && editable; + return getConfigScreen().isEditable() && editable && isEnabled(); } public void setEditable(boolean editable) { diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/DisableableWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/api/DisableableWidget.java new file mode 100644 index 00000000..665538b4 --- /dev/null +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/DisableableWidget.java @@ -0,0 +1,46 @@ +/* + * This file is part of Cloth Config. + * Copyright (C) 2020 - 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.clothconfig2.api; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Experimental +public interface DisableableWidget { + + /** + * Checks whether this config entry gui is enabled. + * + *

Requirements are checked independently (once per tick). This method simply reads the result of the latest + * check, making it extremely cheap to run. + * + *

If {@link HideableWidget#isDisplayed()} is false, this will also be false. + * + * @return whether the config entry is enabled + * @see HideableWidget#isDisplayed() + * @see TickableWidget#tick() + */ + boolean isEnabled(); + + void setRequirement(@Nullable Requirement requirement); + + @Nullable Requirement getRequirement(); + +} diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/HideableWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/api/HideableWidget.java new file mode 100644 index 00000000..16838a84 --- /dev/null +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/HideableWidget.java @@ -0,0 +1,43 @@ +/* + * This file is part of Cloth Config. + * Copyright (C) 2020 - 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.clothconfig2.api; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Experimental +public interface HideableWidget { + + /** + * Checks whether this config entry gui is shown on screen. + * + *

Requirements are checked independently (once per tick). This method simply reads the result of the latest + * check, making it extremely cheap to run. + * + * @return whether to display the config entry + * @see DisableableWidget#isEnabled() + * @see TickableWidget#tick() + */ + boolean isDisplayed(); + + void setDisplayRequirement(@Nullable Requirement requirement); + + @Nullable Requirement getDisplayRequirement(); +} diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/Requirement.java b/common/src/main/java/me/shedaniel/clothconfig2/api/Requirement.java new file mode 100644 index 00000000..f298b7e3 --- /dev/null +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/Requirement.java @@ -0,0 +1,124 @@ +/* + * This file is part of Cloth Config. + * Copyright (C) 2020 - 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.clothconfig2.api; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Represents a predicate (boolean-valued function) without arguments. + * + *

This is a functional interface + * whose functional method is {@link #check()}. + */ +@FunctionalInterface +@ApiStatus.Experimental +public interface Requirement { + + /** + * Checks if this requirement is currently true. + */ + boolean check(); + + /** + * Generates a {@link Requirement} that is true when {@code dependency}'s value is one of the provided values. + */ + @SafeVarargs + static Requirement isValue(ValueHolder dependency, @Nullable T firstValue, @Nullable T... otherValues) { + Set<@Nullable T> values = Stream.concat(Stream.of(firstValue), Arrays.stream(otherValues)) + .collect(Collectors.toCollection(HashSet::new)); + + return () -> values.contains(dependency.getValue()); + } + + /** + * Generates a {@link Requirement} that is true when {@code firstDependency}'s value equals {@code secondDependency}'s value. + */ + static Requirement matches(ValueHolder firstDependency, ValueHolder secondDependency) { + return () -> Objects.equals(firstDependency.getValue(), secondDependency.getValue()); + } + + /** + * Generates a {@link Requirement} that is true when {@code dependency}'s value is true. + */ + static Requirement isTrue(ValueHolder dependency) { + return () -> Boolean.TRUE.equals(dependency.getValue()); + } + + /** + * Generates a {@link Requirement} that is true when {@code dependency}'s value is false. + */ + static Requirement isFalse(ValueHolder dependency) { + return () -> Boolean.FALSE.equals(dependency.getValue()); + } + + /** + * Generates a {@link Requirement} that is true when the given {@code requirement} is false. + */ + static Requirement not(Requirement requirement) { + return () -> !requirement.check(); + } + + /** + * Generates a {@link Requirement} that is true when all the given requirements are true. + */ + static Requirement all(Requirement... requirements) { + return () -> Arrays.stream(requirements).allMatch(Requirement::check); + } + + /** + * Generates a {@link Requirement} that is true when any of the given requirements are true. + */ + static Requirement any(Requirement... requirements) { + return () -> Arrays.stream(requirements).anyMatch(Requirement::check); + } + + /** + * Generates a {@link Requirement} that is true when none of the given requirements are true, i.e. all are false. + */ + static Requirement none(Requirement... requirements) { + return () -> Arrays.stream(requirements).noneMatch(Requirement::check); + } + + /** + * Generates a {@link Requirement} that is true when precisely one of the given requirements is true. + */ + static Requirement one(Requirement... requirements) { + return () -> { + // Use a for loop instead of Stream.count() so that we can return early. We only need to count past 1. + boolean oneFound = false; + for (Requirement requirement : requirements) { + if (!requirement.check()) + continue; + if (oneFound) + return false; + oneFound = true; + } + return oneFound; + }; + } +} diff --git a/common/src/main/java/me/shedaniel/clothconfig2/api/ValueHolder.java b/common/src/main/java/me/shedaniel/clothconfig2/api/ValueHolder.java new file mode 100644 index 00000000..7bb84ba0 --- /dev/null +++ b/common/src/main/java/me/shedaniel/clothconfig2/api/ValueHolder.java @@ -0,0 +1,33 @@ +/* + * This file is part of Cloth Config. + * Copyright (C) 2020 - 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.clothconfig2.api; + +import org.jetbrains.annotations.Nullable; + +public interface ValueHolder { + /** + * Get the value held by this Value Holder. + * + *

Depending on the implementation, this method may or may not be {@link Nullable}. + * + * @return the current value. + */ + T getValue(); +} diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java index 5707842f..4ff15647 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java @@ -355,7 +355,7 @@ protected void renderItem(PoseStack matrices, R item, int index, int y, int x, i } @Override - protected void renderList(PoseStack matrices, int startX, int startY, int int_3, int int_4, float delta) { + protected void renderList(PoseStack matrices, int startX, int startY, int mouseX, int mouseY, float delta) { thisTimeTarget = null; Rectangle hoverBounds = currentBounds.value(); if (!hoverBounds.isEmpty()) { @@ -364,8 +364,8 @@ protected void renderList(PoseStack matrices, int startX, int startY, int int_3, alpha = (alpha * 36 / 255) << 24; GuiComponent.fillGradient(matrices, hoverBounds.x, hoverBounds.y - (int) scroll, hoverBounds.getMaxX(), hoverBounds.getMaxY() - (int) scroll, 0xFFFFFF | alpha, 0xFFFFFF | alpha); } - super.renderList(matrices, startX, startY, int_3, int_4, delta); - if (thisTimeTarget != null && isMouseOver(int_3, int_4)) { + super.renderList(matrices, startX, startY, mouseX, mouseY, delta); + if (thisTimeTarget != null && isMouseOver(mouseX, mouseY)) { lastTouch = System.currentTimeMillis(); } if (thisTimeTarget != null && !thisTimeTarget.equals(currentBounds.target())) { diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java index 3eb08a31..ceb7af72 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java @@ -115,7 +115,7 @@ public BaseListEntry(@NotNull Component fieldName, @Nullable Supplier> getDefaultValue() { @Override public int getItemHeight() { - if (expanded) { + if (isExpanded()) { int i = 24; for (BaseListCell entry : cells) i += entry.getCellHeight(); @@ -222,7 +222,7 @@ public int getItemHeight() { @Override public List children() { - if (!expanded) { + if (!isExpanded()) { List elements = new ArrayList<>(widgets); elements.removeAll(cells); return elements; @@ -278,9 +278,7 @@ public Optional getTooltip(int mouseX, int mouseY) { return Optional.of(new Component[]{addTooltip}); if (removeTooltip != null && isInsideDelete(mouseX, mouseY)) return Optional.of(new Component[]{removeTooltip}); - if (getTooltipSupplier() != null) - return getTooltipSupplier().get(); - return Optional.empty(); + return super.getTooltip(mouseX, mouseY); } @Override @@ -288,10 +286,11 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isHovered, delta); RenderSystem.setShaderTexture(0, CONFIG_TEX); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - BaseListCell focused = !expanded || getFocused() == null || !(getFocused() instanceof BaseListCell) ? null : (BaseListCell) getFocused(); + BaseListCell focused = !isExpanded() || getFocused() == null || !(getFocused() instanceof BaseListCell) ? null : (BaseListCell) getFocused(); + boolean insideLabel = labelWidget.rectangle.contains(mouseX, mouseY); boolean insideCreateNew = isInsideCreateNew(mouseX, mouseY); boolean insideDelete = isInsideDelete(mouseX, mouseY); - blit(matrices, x - 15, y + 5, 24 + 9, (labelWidget.rectangle.contains(mouseX, mouseY) && !insideCreateNew && !insideDelete ? 18 : 0) + (expanded ? 9 : 0), 9, 9); + blit(matrices, x - 15, y + 5, 24 + 9, (isEnabled() ? (insideLabel && !insideCreateNew && !insideDelete ? 18 : 0) : 36) + (isExpanded() ? 9 : 0), 9, 9); if (isInsertButtonEnabled()) blit(matrices, x - 15 + 13, y + 5, 24 + 18, insideCreateNew ? 9 : 0, 9, 9); if (isDeleteButtonEnabled()) @@ -300,8 +299,9 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, resetWidget.setY(y); resetWidget.active = isEditable() && getDefaultValue().isPresent() && !isMatchDefault(); resetWidget.render(matrices, mouseX, mouseY, delta); - Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), isDeleteButtonEnabled() ? x + 24 : x + 24 - 9, y + 6, labelWidget.rectangle.contains(mouseX, mouseY) && !resetWidget.isMouseOver(mouseX, mouseY) && !insideDelete && !insideCreateNew ? 0xffe6fe16 : getPreferredTextColor()); - if (expanded) { + int offset = (isInsertButtonEnabled() || isDeleteButtonEnabled() ? 6 : 0) + (isInsertButtonEnabled() ? 9 : 0) + (isDeleteButtonEnabled() ? 9 : 0); + Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), x + offset, y + 6, insideLabel && !resetWidget.isMouseOver(mouseX, mouseY) && !insideDelete && !insideCreateNew ? 0xffe6fe16 : getPreferredTextColor()); + if (isExpanded()) { int yy = y + 24; for (BaseListCell cell : cells) { cell.render(matrices, -1, yy, x + 14, entryWidth - 14, cell.getCellHeight(), mouseX, mouseY, getParent().getFocused() != null && getParent().getFocused().equals(this) && getFocused() != null && getFocused().equals(cell), delta); @@ -313,7 +313,7 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, @Override public void updateSelected(boolean isSelected) { for (C cell : cells) { - cell.updateSelected(isSelected && getFocused() == cell && expanded); + cell.updateSelected(isSelected && getFocused() == cell && isExpanded()); } } @@ -330,11 +330,13 @@ public class ListLabelWidget implements GuiEventListener { protected Rectangle rectangle = new Rectangle(); @Override - public boolean mouseClicked(double double_1, double double_2, int int_1) { - if (resetWidget.isMouseOver(double_1, double_2)) { + public boolean mouseClicked(double mouseX, double mouseY, int int_1) { + if (!isEnabled()) return false; - } else if (isInsideCreateNew(double_1, double_2)) { - expanded = true; + if (resetWidget.isMouseOver(mouseX, mouseY)) { + return false; + } else if (isInsideCreateNew(mouseX, mouseY)) { + setExpanded(true); C cell; if (insertInFront()) { cells.add(0, cell = createNewInstance.apply(BaseListEntry.this.self())); @@ -346,9 +348,9 @@ public boolean mouseClicked(double double_1, double double_2, int int_1) { cell.onAdd(); Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); return true; - } else if (isDeleteButtonEnabled() && isInsideDelete(double_1, double_2)) { + } else if (isDeleteButtonEnabled() && isInsideDelete(mouseX, mouseY)) { GuiEventListener focused = getFocused(); - if (expanded && focused instanceof BaseListCell) { + if (isExpanded() && focused instanceof BaseListCell) { ((BaseListCell) focused).onDelete(); //noinspection SuspiciousMethodCalls cells.remove(focused); @@ -356,8 +358,8 @@ public boolean mouseClicked(double double_1, double double_2, int int_1) { Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } return true; - } else if (rectangle.contains(double_1, double_2)) { - expanded = !expanded; + } else if (rectangle.contains(mouseX, mouseY)) { + setExpanded(!expanded); Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); return true; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java index 361ea56b..c52d2c66 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/MultiElementListEntry.java @@ -114,15 +114,16 @@ public Optional getDefaultValue() { @Override public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isHovered, delta); + boolean insideWidget = widget.rectangle.contains(mouseX, mouseY); RenderSystem.setShaderTexture(0, CONFIG_TEX); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - blit(matrices, x - 15, y + 5, 24, (widget.rectangle.contains(mouseX, mouseY) ? 18 : 0) + (expanded ? 9 : 0), 9, 9); - Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), x, y + 6, widget.rectangle.contains(mouseX, mouseY) ? 0xffe6fe16 : -1); + blit(matrices, x - 15, y + 5, 24, (isEnabled() ? (insideWidget ? 18 : 0) : 36) + (isExpanded() ? 9 : 0), 9, 9); + Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), x, y + 6, insideWidget ? 0xffe6fe16 : -1); for (AbstractConfigListEntry entry : entries) { entry.setParent(getParent()); entry.setScreen(getConfigScreen()); } - if (expanded) { + if (isExpanded()) { int yy = y + 24; for (AbstractConfigListEntry entry : entries) { entry.render(matrices, -1, yy, x + 14, entryWidth - 14, entry.getItemHeight(), mouseX, mouseY, isHovered, delta); @@ -143,7 +144,7 @@ public Rectangle getEntryArea(int x, int y, int entryWidth, int entryHeight) { @Override public int getItemHeight() { - if (expanded) { + if (isExpanded()) { int i = 24; for (AbstractConfigListEntry entry : entries) i += entry.getItemHeight(); @@ -155,7 +156,7 @@ public int getItemHeight() { @Override public void updateSelected(boolean isSelected) { for (AbstractConfigListEntry entry : entries) { - entry.updateSelected(expanded && isSelected && getFocused() == entry); + entry.updateSelected(isExpanded() && isSelected && getFocused() == entry); } } @@ -166,7 +167,7 @@ public int getInitialReferenceOffset() { @Override public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (expanded) { + if (isExpanded()) { for (AbstractConfigListEntry entry : entries) { entry.lateRender(matrices, mouseX, mouseY, delta); } @@ -176,7 +177,7 @@ public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) @SuppressWarnings("deprecation") @Override public int getMorePossibleHeight() { - if (!expanded) return -1; + if (!isExpanded()) return -1; List list = new ArrayList<>(); int i = 24; for (AbstractConfigListEntry entry : entries) { @@ -191,12 +192,12 @@ public int getMorePossibleHeight() { @Override public List children() { - return expanded ? (List) children : Collections.singletonList(widget); + return isExpanded() ? (List) children : Collections.singletonList(widget); } @Override public List narratables() { - return expanded ? (List) children : Collections.singletonList(widget); + return isExpanded() ? (List) children : Collections.singletonList(widget); } @Override @@ -216,7 +217,7 @@ public Optional getError() { @Override public boolean isExpanded() { - return this.expanded; + return this.expanded && isEnabled(); } @Override @@ -229,9 +230,9 @@ public class CategoryLabelWidget implements GuiEventListener, NarratableEntry { private boolean isHovered; @Override - public boolean mouseClicked(double double_1, double double_2, int int_1) { - if (rectangle.contains(double_1, double_2)) { - expanded = !expanded; + public boolean mouseClicked(double mouseX, double mouseY, int int_1) { + if (isEnabled() && rectangle.contains(mouseX, mouseY)) { + setExpanded(!expanded); Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); return isHovered = true; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java index d4d2b56b..664a1fbc 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java @@ -71,7 +71,7 @@ public Iterator getSearchTags() { @Override public boolean isExpanded() { - return expanded; + return expanded && isEnabled(); } @Override @@ -106,7 +106,7 @@ public List filteredEntries() { @Override public Iterator iterator() { return Iterators.filter(entries.iterator(), entry -> { - return getConfigScreen() != null && getConfigScreen().matchesSearch(entry.getSearchTags()); + return entry.isDisplayed() && getConfigScreen() != null && getConfigScreen().matchesSearch(entry.getSearchTags()); }); } @@ -132,13 +132,14 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isHovered, delta); RenderSystem.setShaderTexture(0, CONFIG_TEX); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - blit(matrices, x - 15, y + 5, 24, (widget.rectangle.contains(mouseX, mouseY) ? 18 : 0) + (expanded ? 9 : 0), 9, 9); - Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), x, y + 6, widget.rectangle.contains(mouseX, mouseY) ? 0xffe6fe16 : -1); + boolean insideWidget = widget.rectangle.contains(mouseX, mouseY); + blit(matrices, x - 15, y + 5, 24, (isEnabled() ? (insideWidget ? 18 : 0) : 36) + (isExpanded() ? 9 : 0), 9, 9); + Minecraft.getInstance().font.drawShadow(matrices, getDisplayedFieldName().getVisualOrderText(), x, y + 6, insideWidget ? 0xffe6fe16 : 0xffffffff); for (AbstractConfigListEntry entry : entries) { entry.setParent((DynamicEntryListWidget) getParent()); entry.setScreen(getConfigScreen()); } - if (expanded) { + if (isExpanded()) { int yy = y + 24; for (AbstractConfigListEntry entry : filteredEntries()) { entry.render(matrices, -1, yy, x + 14, entryWidth - 14, entry.getItemHeight(), mouseX, mouseY, isHovered && getFocused() == entry, delta); @@ -147,10 +148,18 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, } } + @Override + public void tick() { + super.tick(); + for (AbstractConfigListEntry entry : entries) { + entry.tick(); + } + } + @Override public void updateSelected(boolean isSelected) { for (AbstractConfigListEntry entry : entries) { - entry.updateSelected(expanded && isSelected && getFocused() == entry && getConfigScreen().matchesSearch(entry.getSearchTags())); + entry.updateSelected(isExpanded() && isSelected && getFocused() == entry && entry.isDisplayed() && getConfigScreen().matchesSearch(entry.getSearchTags())); } } @@ -204,7 +213,7 @@ public boolean isEdited() { @Override public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (expanded) { + if (isExpanded()) { for (AbstractConfigListEntry entry : filteredEntries()) { entry.lateRender(matrices, mouseX, mouseY, delta); } @@ -214,7 +223,7 @@ public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) @SuppressWarnings("deprecation") @Override public int getMorePossibleHeight() { - if (!expanded) return -1; + if (!isExpanded()) return -1; List list = new ArrayList<>(); int i = 24; for (AbstractConfigListEntry entry : filteredEntries()) { @@ -238,7 +247,7 @@ public Rectangle getEntryArea(int x, int y, int entryWidth, int entryHeight) { @Override public int getItemHeight() { - if (expanded) { + if (isExpanded()) { int i = 24; for (AbstractConfigListEntry entry : filteredEntries()) i += entry.getItemHeight(); @@ -254,12 +263,12 @@ public int getInitialReferenceOffset() { @Override public List children() { - return expanded ? (List) children : Collections.singletonList(widget); + return isExpanded() ? (List) children : Collections.singletonList(widget); } @Override public List narratables() { - return expanded ? (List) children : Collections.singletonList(widget); + return isExpanded() ? (List) children : Collections.singletonList(widget); } @Override @@ -286,9 +295,9 @@ public class CategoryLabelWidget implements GuiEventListener, NarratableEntry { private boolean isHovered; @Override - public boolean mouseClicked(double double_1, double double_2, int int_1) { - if (rectangle.contains(double_1, double_2)) { - expanded = !expanded; + public boolean mouseClicked(double mouseX, double mouseY, int int_1) { + if (isEnabled() && rectangle.contains(mouseX, mouseY)) { + setExpanded(!expanded); Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); return isHovered = true; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java index c3b45d32..3fb26d3c 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TextListEntry.java @@ -23,6 +23,7 @@ import me.shedaniel.clothconfig2.gui.AbstractConfigScreen; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -36,12 +37,14 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; @Environment(EnvType.CLIENT) public class TextListEntry extends TooltipListEntry { public static final int LINE_HEIGHT = 12; + public static final int DISABLED_COLOR = Objects.requireNonNull(ChatFormatting.DARK_GRAY.getColor()); private final Font textRenderer = Minecraft.getInstance().font; private final int color; private final Component text; @@ -81,8 +84,9 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, this.savedY = y; } int yy = y + 7; + int textColor = isEnabled() ? color : DISABLED_COLOR; for (FormattedCharSequence string : wrappedLines) { - Minecraft.getInstance().font.drawShadow(matrices, string, x, yy, color); + Minecraft.getInstance().font.drawShadow(matrices, string, x, yy, textColor); yy += Minecraft.getInstance().font.lineHeight + 3; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java index fbb73955..f19da49a 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/entries/TooltipListEntry.java @@ -25,15 +25,14 @@ import me.shedaniel.math.Point; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; -import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Optional; import java.util.function.Supplier; +import java.util.stream.Stream; @Environment(EnvType.CLIENT) public abstract class TooltipListEntry extends AbstractConfigListEntry { @@ -56,21 +55,25 @@ public TooltipListEntry(Component fieldName, @Nullable Supplier tooltip = getTooltip(mouseX, mouseY); - if (tooltip.isPresent() && tooltip.get().length > 0) - addTooltip(Tooltip.of(new Point(mouseX, mouseY), postProcessTooltip(tooltip.get()))); + getTooltip(mouseX, mouseY) + .map(lines -> Tooltip.of(new Point(mouseX, mouseY), wrapLinesToScreen(lines))) + .ifPresent(this::addTooltip); } } - private FormattedCharSequence[] postProcessTooltip(Component[] tooltip) { - return Arrays.stream(tooltip).flatMap(component -> Minecraft.getInstance().font.split(component, getConfigScreen().width).stream()) - .toArray(FormattedCharSequence[]::new); - } - public Optional getTooltip() { - if (tooltipSupplier != null) - return tooltipSupplier.get(); - return Optional.empty(); + Stream tooltipStream = Stream.ofNullable(tooltipSupplier) + .map(Supplier::get) + .flatMap(Optional::stream) + .flatMap(Arrays::stream); + + @Nullable Component disabled = this.isEnabled() ? null : Component.translatable("text.cloth-config.disabled_tooltip"); + + Component[] lines = Stream.concat(tooltipStream, Stream.ofNullable(disabled)) + .toArray(Component[]::new); + + return lines.length < 1 ? Optional.empty() : Optional.of(lines); + } public Optional getTooltip(int mouseX, int mouseY) { @@ -85,5 +88,5 @@ public Supplier> getTooltipSupplier() { public void setTooltipSupplier(@Nullable Supplier> tooltipSupplier) { this.tooltipSupplier = tooltipSupplier; } - + } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java index 7a64b4ef..0c4c50b4 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicElementListWidget.java @@ -149,10 +149,6 @@ public void setDragging(boolean bl) { this.dragging = bl; } - public boolean mouseClicked(double d, double e, int i) { - return ContainerEventHandler.super.mouseClicked(d, e, i); - } - @Nullable public GuiEventListener getFocused() { return this.focused; @@ -242,6 +238,62 @@ public NarrationPriority narrationPriority() { return NarrationPriority.NONE; } } + + @Override + public boolean mouseClicked(double d, double e, int i) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.mouseClicked(d, e, i); + } + + @Override + public boolean mouseReleased(double d, double e, int i) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.mouseReleased(d, e, i); + } + + @Override + public boolean mouseDragged(double d, double e, int i, double f, double g) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.mouseDragged(d, e, i, f, g); + } + + @Override + public boolean mouseScrolled(double d, double e, double f) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.mouseScrolled(d, e, f); + } + + @Override + public boolean keyPressed(int i, int j, int k) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.keyPressed(i, j, k); + } + + @Override + public boolean keyReleased(int i, int j, int k) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.keyReleased(i, j, k); + } + + @Override + public boolean charTyped(char c, int i) { + if (!isEnabled()) { + return false; + } + return ContainerEventHandler.super.charTyped(c, i); + } } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java index 499a3e37..efbeace5 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java @@ -22,7 +22,7 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.clothconfig2.api.*; import me.shedaniel.math.Rectangle; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -46,10 +46,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.function.Predicate; @Environment(EnvType.CLIENT) @@ -57,6 +54,8 @@ public abstract class DynamicEntryListWidget entries = new Entries(); + private float totalTicks = 1.0f; + private List visibleEntries = Collections.emptyList(); public int width; public int height; public int top; @@ -86,6 +85,25 @@ public DynamicEntryListWidget(Minecraft client, int width, int height, int top, this.backgroundLocation = backgroundLocation; } + /** + * Get all visible children. I.e. hidden config entries are filtered out. + * + *

Note: this isn't thread safe, since the visible children list is + * updated when calling {@link #tickList()}. + * + * @return an unmodifiable {@link List} of visible entries + */ + @ApiStatus.Experimental + public List visibleChildren() { + return this.visibleEntries; + } + + private void updateVisibleChildren() { + this.visibleEntries = this.children().stream() + .filter(HideableWidget::isDisplayed) + .toList(); + } + public void setRenderSelection(boolean boolean_1) { this.selectionVisible = boolean_1; } @@ -122,7 +140,7 @@ public void updateNarration(NarrationElementOutput narrationElementOutput) { } protected void narrateListElementPosition(NarrationElementOutput narrationElementOutput, E entry) { - List list = this.children(); + List list = this.visibleChildren(); if (list.size() > 1) { int i = list.indexOf(entry); if (i != -1) { @@ -156,7 +174,7 @@ protected final void clearItems() { } protected E getItem(int index) { - return this.children().get(index); + return this.visibleChildren().get(index); } protected int addItem(E item) { @@ -165,11 +183,11 @@ protected int addItem(E item) { } protected int getItemCount() { - return this.children().size(); + return this.visibleChildren().size(); } protected boolean isSelected(int index) { - return Objects.equals(this.getSelectedItem(), this.children().get(index)); + return Objects.equals(this.getSelectedItem(), this.getItem(index)); } protected final E getItemAtPosition(double mouseX, double mouseY) { @@ -177,17 +195,29 @@ protected final E getItemAtPosition(double mouseX, double mouseY) { int minX = listMiddleX - this.getItemWidth() / 2; int maxX = listMiddleX + this.getItemWidth() / 2; int currentY = Mth.floor(mouseY - (double) this.top) - this.headerHeight + (int) this.getScroll() - 4; + + // Check if we can return early + if ((double) this.getScrollbarPosition() <= mouseX) { + return null; + } else if (mouseX < minX) { + return null; + } else if (mouseX > maxX) { + return null; + } else if (currentY < 0) { + return null; + } + + // Otherwise look for the selected item + E itemAtPosition = null; int itemY = 0; - int itemIndex = -1; - for (int i = 0; i < children().size(); i++) { - E item = getItem(i); + for (E item : visibleChildren()) { itemY += item.getItemHeight(); if (itemY > currentY) { - itemIndex = i; + itemAtPosition = item; break; } } - return mouseX < (double) this.getScrollbarPosition() && mouseX >= minX && mouseX <= maxX && itemIndex >= 0 && currentY >= 0 && itemIndex < this.getItemCount() ? this.children().get(itemIndex) : null; + return itemAtPosition; } public void updateSize(int width, int height, int top, int bottom) { @@ -207,7 +237,7 @@ public void setLeftPos(int left) { protected int getMaxScrollPosition() { List list = new ArrayList<>(); int i = headerHeight; - for (E entry : children()) { + for (E entry : visibleChildren()) { i += entry.getItemHeight(); if (entry.getMorePossibleHeight() >= 0) { list.add(i + entry.getMorePossibleHeight()); @@ -220,6 +250,13 @@ protected int getMaxScrollPosition() { protected void clickedHeader(int int_1, int int_2) { } + public void tickList() { + this.updateVisibleChildren(); + for (E child : this.children()) { + child.tick(); + } + } + protected void renderHeader(PoseStack matrices, int rowLeft, int startY, Tesselator tessellator) { } @@ -246,6 +283,12 @@ protected void renderBackBackground(PoseStack matrices, BufferBuilder buffer, Te @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + this.totalTicks += delta; + if (this.totalTicks >= 1.0f) { + this.totalTicks = this.totalTicks % 1.0f; + this.tickList(); + } + this.drawBackground(); int scrollbarPosition = this.getScrollbarPosition(); int int_4 = scrollbarPosition + 6; @@ -289,14 +332,21 @@ protected void renderScrollBar(PoseStack matrices, Tesselator tessellator, Buffe } protected void centerScrollOn(E item) { - double d = (this.bottom - this.top) / -2d; - for (int i = 0; i < this.children().indexOf(item) && i < this.getItemCount(); i++) - d += getItem(i).getItemHeight(); - this.capYPosition(d); + List children = this.visibleChildren(); + double halfway = (this.bottom - this.top) / -2d; + int itemIndex = children.indexOf(item); + int i = 0; + for (E elm : children) { + if (i++ >= itemIndex) { + break; + } + halfway += elm.getItemHeight(); + } + this.capYPosition(halfway); } protected void ensureVisible(E item) { - ensureVisible((int) this.getScroll() - top - headerHeight - 4 + this.getRowTop(this.children().indexOf(item)), item.getItemHeight()); + ensureVisible((int) this.getScroll() - top - headerHeight - 4 + this.getRowTop(this.visibleChildren().indexOf(item)), item.getItemHeight()); } public void ensureVisible(int rowTop, int itemHeight) { @@ -446,7 +496,7 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del } public boolean mouseScrolled(double double_1, double double_2, double double_3) { - for (E entry : children()) { + for (E entry : visibleChildren()) { if (entry.mouseScrolled(double_1, double_2, double_3)) { return true; } @@ -469,44 +519,51 @@ public boolean keyPressed(int int_1, int int_2, int int_3) { } } - protected void moveSelection(int int_1) { - if (!this.children().isEmpty()) { - int int_2 = this.children().indexOf(this.getSelectedItem()); - int int_3 = Mth.clamp(int_2 + int_1, 0, this.getItemCount() - 1); - E itemListWidget$Item_1 = this.children().get(int_3); - this.selectItem(itemListWidget$Item_1); - this.ensureVisible(itemListWidget$Item_1); + protected void moveSelection(int shift) { + List children = this.visibleChildren(); + if (children.isEmpty()) { + return; } - + int selected = children.indexOf(this.getSelectedItem()); + int index = Mth.clamp(selected + shift, 0, this.getItemCount() - 1); + E item = this.getItem(index); + this.selectItem(item); + this.ensureVisible(item); } public boolean isMouseOver(double double_1, double double_2) { return double_2 >= (double) this.top && double_2 <= (double) this.bottom && double_1 >= (double) this.left && double_1 <= (double) this.right; } - protected void renderList(PoseStack matrices, int startX, int startY, int int_3, int int_4, float float_1) { - hoveredItem = this.isMouseOver(int_3, int_4) ? this.getItemAtPosition(int_3, int_4) : null; - int itemCount = this.getItemCount(); + protected void renderList(PoseStack matrices, int startX, int startY, int mouseX, int mouseY, float delta) { Tesselator tesselator = Tesselator.getInstance(); BufferBuilder buffer = tesselator.getBuilder(); - for (int renderIndex = 0; renderIndex < itemCount; ++renderIndex) { - E item = this.getItem(renderIndex); - int itemY = startY + headerHeight; - for (int i = 0; i < children().size() && i < renderIndex; i++) - itemY += children().get(i).getItemHeight(); + hoveredItem = this.isMouseOver(mouseX, mouseY) ? this.getItemAtPosition(mouseX, mouseY) : null; + + int heights = 0; // itemHeight accumulator + int renderIndex = 0; // index is passed to render methods + for (E item : visibleChildren()) { + int itemY = startY + headerHeight + heights; int itemHeight = item.getItemHeight() - 4; int itemWidth = this.getItemWidth(); - if (this.selectionVisible && this.isSelected(renderIndex)) { + boolean itemHovered = Objects.equals(this.hoveredItem, item); + + if (this.selectionVisible && Objects.equals(this.selectedItem, item)) { int itemMinX = this.left + (this.width - itemWidth) / 2; int itemMaxX = this.left + (this.width + itemWidth) / 2; fill(matrices, itemMinX, itemY - 2, itemMaxX, itemY + itemHeight + 2, this.isFocused() ? 0xffffffff : 0xff808080); fill(matrices, itemMinX + 1, itemY - 1, itemMaxX - 1, itemY + itemHeight + 1, 0xff000000); } + // Finally, call render int y = this.getRowTop(renderIndex); int x = this.getRowLeft(); - renderItem(matrices, item, renderIndex, y, x, itemWidth, itemHeight, int_3, int_4, Objects.equals(hoveredItem, item), float_1); + renderItem(matrices, item, renderIndex, y, x, itemWidth, itemHeight, mouseX, mouseY, itemHovered, delta); + + // Update counter and accumulator + heights += item.getItemHeight(); + renderIndex++; } } @@ -519,10 +576,15 @@ protected int getRowLeft() { } public int getRowTop(int index) { - int integer = top + 4 - (int) this.getScroll() + headerHeight; - for (int i = 0; i < children().size() && i < index; i++) - integer += children().get(i).getItemHeight(); - return integer; + int top = this.top + 4 - (int) this.getScroll() + headerHeight; + int i = 0; + for (E item : visibleChildren()) { + if (index <= i++) { + break; + } + top += item.getItemHeight(); + } + return top; } @Override @@ -545,18 +607,18 @@ protected void renderHoleBackground(PoseStack matrices, int y1, int y2, int alph tesselator.end(); } - protected E remove(int int_1) { - E itemListWidget$Item_1 = this.children().get(int_1); - return this.removeEntry(this.children().get(int_1)) ? itemListWidget$Item_1 : null; + protected E remove(int index) { + E item = this.getItem(index); + return this.removeEntry(item) ? item : null; } - protected boolean removeEntry(E itemListWidget$Item_1) { - boolean boolean_1 = this.children().remove(itemListWidget$Item_1); - if (boolean_1 && itemListWidget$Item_1 == this.getSelectedItem()) { + protected boolean removeEntry(E entry) { + boolean removed = this.children().remove(entry); + if (removed && entry == this.getSelectedItem()) { this.selectItem(null); } - return boolean_1; + return removed; } public static final class SmoothScrollingSettings { @@ -566,10 +628,16 @@ private SmoothScrollingSettings() {} } @Environment(EnvType.CLIENT) - public abstract static class Entry> extends GuiComponent implements GuiEventListener { + public abstract static class Entry> extends GuiComponent implements GuiEventListener, TickableWidget, HideableWidget, DisableableWidget { @Deprecated DynamicEntryListWidget parent; @Nullable private NarratableEntry lastNarratable; + @Nullable + protected Requirement enableRequirement = null; + @Nullable + protected Requirement displayRequirement = null; + protected boolean enabled = true; + protected boolean displayed = true; public Entry() { } @@ -588,6 +656,36 @@ public void setParent(DynamicEntryListWidget parent) { this.parent = parent; } + @Override + public boolean isEnabled() { + return isDisplayed() && enabled; + } + + @Override + public boolean isDisplayed() { + return displayed; + } + + @Override + public void setRequirement(@Nullable Requirement requirement) { + this.enableRequirement = requirement; + } + + @Override + public @Nullable Requirement getRequirement() { + return enableRequirement; + } + + @Override + public void setDisplayRequirement(@Nullable Requirement requirement) { + this.displayRequirement = requirement; + } + + @Override + public @Nullable Requirement getDisplayRequirement() { + return displayRequirement; + } + public abstract int getItemHeight(); @Deprecated @@ -597,6 +695,13 @@ public int getMorePossibleHeight() { public abstract List narratables(); + @Override + public void tick() { + // Check requirements + enabled = getRequirement() == null || getRequirement().check(); + displayed = getDisplayRequirement() == null || getDisplayRequirement().check(); + } + void updateNarration(NarrationElementOutput narrationElementOutput) { List list = this.narratables(); Screen.NarratableSearchResult narratableSearchResult = Screen.findNarratableWidget(list, this.lastNarratable); diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java index e5845746..14a9e2c4 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java @@ -89,7 +89,7 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - for (E entry : children()) { + for (E entry : visibleChildren()) { if (entry.mouseScrolled(mouseX, mouseY, amount)) { return true; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicSmoothScrollingEntryListWidget.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicSmoothScrollingEntryListWidget.java index 4bdd5ad2..0dd7dcfa 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicSmoothScrollingEntryListWidget.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicSmoothScrollingEntryListWidget.java @@ -90,7 +90,7 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - for (E entry : children()) { + for (E entry : visibleChildren()) { if (entry.mouseScrolled(mouseX, mouseY, amount)) { return true; } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/SearchFieldEntry.java b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/SearchFieldEntry.java index ca16bcda..7f704021 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/SearchFieldEntry.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/gui/widget/SearchFieldEntry.java @@ -52,7 +52,7 @@ public Iterator>> iterator() { if (editBox.getValue().isEmpty()) return entries.iterator(); return Iterators.filter(entries.iterator(), entry -> { - return screen.matchesSearch(entry.getSearchTags()); + return entry.isDisplayed() && screen.matchesSearch(entry.getSearchTags()); }); } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java index 51abb24c..ea60463e 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/BooleanToggleBuilder.java @@ -109,7 +109,7 @@ public Component getYesNoText(boolean bool) { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java index 9eff4dd5..d55d9f6f 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/ColorFieldBuilder.java @@ -127,7 +127,7 @@ public ColorEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java index 3a6a25a8..58a810b7 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleFieldBuilder.java @@ -114,7 +114,7 @@ public DoubleListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleListBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleListBuilder.java index af5108af..3d219155 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleListBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DoubleListBuilder.java @@ -162,7 +162,7 @@ public DoubleListListEntry build() { entry.setRemoveTooltip(getRemoveTooltip()); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DropdownMenuBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DropdownMenuBuilder.java index 0690c6fd..1a59eec9 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DropdownMenuBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/DropdownMenuBuilder.java @@ -127,7 +127,7 @@ public DropdownBoxEntry build() { if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); entry.setSuggestionMode(suggestionMode); - return entry; + return finishBuilding(entry); } public static class TopCellElementBuilder { diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/EnumSelectorBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/EnumSelectorBuilder.java index 95965981..f5017ff2 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/EnumSelectorBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/EnumSelectorBuilder.java @@ -103,7 +103,7 @@ public EnumListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FieldBuilder.java index 6a0a9c10..2a780320 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FieldBuilder.java @@ -20,9 +20,12 @@ package me.shedaniel.clothconfig2.impl.builders; import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.clothconfig2.api.Requirement; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,6 +41,8 @@ public abstract class FieldBuilder defaultValue = null; @Nullable protected Function> errorSupplier; + @Nullable protected Requirement enableRequirement = null; + @Nullable protected Requirement displayRequirement = null; protected FieldBuilder(Component resetButtonKey, Component fieldNameKey) { this.resetButtonKey = Objects.requireNonNull(resetButtonKey); @@ -58,6 +63,25 @@ public final AbstractConfigListEntry buildEntry() { @NotNull public abstract A build(); + /** + * Finishes building the given {@link AbstractConfigListEntry config entry} by applying anything defined in this abstract class. + *

+ * Should be used by implementations of {@link #build()}. + * + * @param gui the config entry to finish building + * @return the mutated config entry + */ + @Contract(value = "_ -> param1", mutates = "param1") + protected A finishBuilding(A gui) { + if (gui == null) + return null; + if (enableRequirement != null) + gui.setRequirement(enableRequirement); + if (displayRequirement != null) + gui.setDisplayRequirement(displayRequirement); + return gui; + } + @NotNull public final Component getFieldNameKey() { return fieldNameKey; @@ -75,4 +99,40 @@ public boolean isRequireRestart() { public void requireRestart(boolean requireRestart) { this.requireRestart = requireRestart; } + + /** + * Set a requirement that controls whether the config entry gui is enabled. + * + *

If an enablement requirement is already set, it will be overwritten. + * + *

If the requirement returns {@code true}, the config entry will be enabled. + * If the requirement returns {@code false}, the config entry will be disabled. + * + * @see Requirement + */ + @Contract(mutates = "this") + @ApiStatus.Experimental + public final SELF setRequirement(Requirement requirement) { + @SuppressWarnings("unchecked") SELF self = (SELF) this; + enableRequirement = requirement; + return self; + } + + /** + * Set a requirement that controls whether the config entry gui is displayed. + * + *

If a display requirement is already set, it will be overwritten. + * + *

If the requirement returns {@code true}, the config entry will be displayed. + * If the requirement returns {@code false}, the config entry will be hidden. + * + * @see Requirement + */ + @Contract(mutates = "this") + @ApiStatus.Experimental + public final SELF setDisplayRequirement(Requirement requirement) { + @SuppressWarnings("unchecked") SELF self = (SELF) this; + displayRequirement = requirement; + return self; + } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatFieldBuilder.java index f49b2c08..221010be 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatFieldBuilder.java @@ -113,7 +113,7 @@ public FloatListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatListBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatListBuilder.java index 100b3975..f1defb7d 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatListBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/FloatListBuilder.java @@ -162,7 +162,7 @@ public FloatListListEntry build() { entry.setRemoveTooltip(getRemoveTooltip()); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntFieldBuilder.java index 58f57507..a265ae10 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntFieldBuilder.java @@ -110,7 +110,7 @@ public IntegerListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntListBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntListBuilder.java index 9c9261dc..20ecabc6 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntListBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntListBuilder.java @@ -163,7 +163,7 @@ public IntegerListListEntry build() { entry.setRemoveTooltip(getRemoveTooltip()); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntSliderBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntSliderBuilder.java index c3ebd1ce..44c071b4 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntSliderBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/IntSliderBuilder.java @@ -119,7 +119,7 @@ public IntegerSliderEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/KeyCodeBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/KeyCodeBuilder.java index a2fa8e1b..03273a53 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/KeyCodeBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/KeyCodeBuilder.java @@ -143,7 +143,7 @@ public KeyCodeEntry build() { entry.setAllowKey(allowKey); entry.setAllowMouse(allowMouse); entry.setAllowModifiers(allowModifiers); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongFieldBuilder.java index 9da53237..815302e3 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongFieldBuilder.java @@ -113,7 +113,7 @@ public LongListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongListBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongListBuilder.java index 4f2cf4e6..112e41b1 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongListBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongListBuilder.java @@ -162,7 +162,7 @@ public LongListListEntry build() { entry.setRemoveTooltip(getRemoveTooltip()); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongSliderBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongSliderBuilder.java index a713a79c..0f22f95a 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongSliderBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/LongSliderBuilder.java @@ -99,7 +99,7 @@ public LongSliderEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SelectorBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SelectorBuilder.java index 2dc66bb6..01112054 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SelectorBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SelectorBuilder.java @@ -100,7 +100,7 @@ public SelectionListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringFieldBuilder.java index d9051baa..cef98904 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringFieldBuilder.java @@ -91,7 +91,7 @@ public StringListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringListBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringListBuilder.java index 6df56a57..31b42789 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringListBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/StringListBuilder.java @@ -138,7 +138,7 @@ public StringListListEntry build() { entry.setRemoveTooltip(getRemoveTooltip()); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SubCategoryBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SubCategoryBuilder.java index cb2d2004..a54150ec 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SubCategoryBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/SubCategoryBuilder.java @@ -78,7 +78,7 @@ public SubCategoryBuilder setExpanded(boolean expanded) { public SubCategoryListEntry build() { SubCategoryListEntry entry = new SubCategoryListEntry(getFieldNameKey(), entries, expanded); entry.setTooltipSupplier(() -> tooltipSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } @Override diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextDescriptionBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextDescriptionBuilder.java index e2c6174d..db26919f 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextDescriptionBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextDescriptionBuilder.java @@ -69,7 +69,7 @@ public TextDescriptionBuilder setColor(int color) { @NotNull @Override public TextListEntry build() { - return new TextListEntry(getFieldNameKey(), value, color, tooltipSupplier); + return finishBuilding(new TextListEntry(getFieldNameKey(), value, color, tooltipSupplier)); } } diff --git a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextFieldBuilder.java b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextFieldBuilder.java index 92b2018e..c2fc939a 100644 --- a/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextFieldBuilder.java +++ b/common/src/main/java/me/shedaniel/clothconfig2/impl/builders/TextFieldBuilder.java @@ -91,7 +91,7 @@ public StringListEntry build() { entry.setTooltipSupplier(() -> getTooltipSupplier().apply(entry.getValue())); if (errorSupplier != null) entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue())); - return entry; + return finishBuilding(entry); } } diff --git a/common/src/main/resources/assets/cloth-config2/lang/en_us.json b/common/src/main/resources/assets/cloth-config2/lang/en_us.json index 63e40b2a..ac745ed5 100644 --- a/common/src/main/resources/assets/cloth-config2/lang/en_us.json +++ b/common/src/main/resources/assets/cloth-config2/lang/en_us.json @@ -33,6 +33,7 @@ "text.cloth-config.boolean.value.true": "§aYes", "text.cloth-config.boolean.value.false": "§cNo", "text.cloth-config.dropdown.value.unknown": "§cNo suggestions", + "text.cloth-config.disabled_tooltip": "Disabled (requirements not met)", "modifier.cloth-config.alt": "Alt + %s", "modifier.cloth-config.ctrl": "Ctrl + %s", "modifier.cloth-config.shift": "Shift + %s", diff --git a/gradle.properties b/gradle.properties index c7ec21e4..a701bb47 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ supported_version=1.19.4 archives_base_name=cloth-config archives_base_name_snapshot=cloth-config-snapshot -base_version=10.0 +base_version=10.1 maven_group=me.shedaniel.cloth jankson_version=1.2.0