aboutsummaryrefslogtreecommitdiff
path: root/src/client/java/dev/isxander/yacl
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/java/dev/isxander/yacl')
-rw-r--r--src/client/java/dev/isxander/yacl/api/LabelOption.java20
-rw-r--r--src/client/java/dev/isxander/yacl/api/Option.java1
-rw-r--r--src/client/java/dev/isxander/yacl/gui/OptionListWidget.java82
-rw-r--r--src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java4
-rw-r--r--src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java113
-rw-r--r--src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java2
6 files changed, 206 insertions, 16 deletions
diff --git a/src/client/java/dev/isxander/yacl/api/LabelOption.java b/src/client/java/dev/isxander/yacl/api/LabelOption.java
new file mode 100644
index 0000000..a1bbe28
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/api/LabelOption.java
@@ -0,0 +1,20 @@
+package dev.isxander.yacl.api;
+
+import dev.isxander.yacl.impl.LabelOptionImpl;
+import net.minecraft.text.Text;
+
+/**
+ * A label option is an easier way of creating a label with a {@link dev.isxander.yacl.gui.controllers.LabelController}.
+ * This option is immutable and cannot be disabled. Tooltips are supported through
+ * {@link Text} styling.
+ */
+public interface LabelOption extends Option<Text> {
+ Text label();
+
+ /**
+ * Creates a new label option with the given label.
+ */
+ static LabelOption create(Text label) {
+ return new LabelOptionImpl(label);
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/api/Option.java b/src/client/java/dev/isxander/yacl/api/Option.java
index 406931f..9b4ff7b 100644
--- a/src/client/java/dev/isxander/yacl/api/Option.java
+++ b/src/client/java/dev/isxander/yacl/api/Option.java
@@ -136,6 +136,7 @@ public interface Option<T> {
*
* @param tooltipGetter function to get tooltip depending on value {@link Builder#build()}.
*/
+ @SuppressWarnings("unchecked")
Builder<T> tooltip(@NotNull Function<T, Text>... tooltipGetter);
/**
diff --git a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java
index c18597f..674fc56 100644
--- a/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java
+++ b/src/client/java/dev/isxander/yacl/gui/OptionListWidget.java
@@ -3,8 +3,6 @@ package dev.isxander.yacl.gui;
import com.google.common.collect.ImmutableList;
import dev.isxander.yacl.api.*;
import dev.isxander.yacl.api.utils.Dimension;
-import dev.isxander.yacl.gui.controllers.ListEntryWidget;
-import dev.isxander.yacl.impl.ListOptionEntryImpl;
import dev.isxander.yacl.impl.utils.YACLConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.MultilineText;
@@ -16,6 +14,7 @@ import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.screen.narration.NarrationPart;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -27,7 +26,7 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
private ImmutableList<Entry> viewableChildren;
public OptionListWidget(YACLScreen screen, MinecraftClient client, int width, int height) {
- super(client, width / 3, 0, width / 3 * 2, height, true);
+ super(client, width / 3, 0, width / 3 * 2 + 1, height, true);
this.yaclScreen = screen;
refreshOptions();
@@ -65,7 +64,17 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
groupSeparatorEntry = null;
}
- List<OptionEntry> optionEntries = new ArrayList<>();
+ List<Entry> optionEntries = new ArrayList<>();
+
+ // add empty entry to make sure users know it's empty not just bugging out
+ if (groupSeparatorEntry instanceof ListGroupSeparatorEntry listGroupSeparatorEntry) {
+ if (listGroupSeparatorEntry.listOption.options().isEmpty()) {
+ EmptyListLabel emptyListLabel = new EmptyListLabel(listGroupSeparatorEntry, category);
+ addEntry(emptyListLabel);
+ optionEntries.add(emptyListLabel);
+ }
+ }
+
for (Option<?> option : group.options()) {
OptionEntry entry = new OptionEntry(option, category, group, groupSeparatorEntry, option.controller().provideWidget(yaclScreen, getDefaultEntryDimension()));
addEntry(entry);
@@ -73,7 +82,7 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
}
if (groupSeparatorEntry != null) {
- groupSeparatorEntry.setOptionEntries(optionEntries);
+ groupSeparatorEntry.setChildEntries(optionEntries);
}
}
}
@@ -85,20 +94,22 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
private void refreshListEntries(ListOption<?> listOption, ConfigCategory category) {
// find group separator for group
- GroupSeparatorEntry groupSeparator = super.children().stream().filter(e -> e instanceof GroupSeparatorEntry gs && gs.group == listOption).map(GroupSeparatorEntry.class::cast).findAny().orElse(null);
+ ListGroupSeparatorEntry groupSeparator = super.children().stream().filter(e -> e instanceof ListGroupSeparatorEntry gs && gs.group == listOption).map(ListGroupSeparatorEntry.class::cast).findAny().orElse(null);
if (groupSeparator == null) {
YACLConstants.LOGGER.warn("Can't find group seperator to refresh list option entries for list option " + listOption.name());
return;
}
- for (OptionEntry entry : groupSeparator.optionEntries)
+ for (Entry entry : groupSeparator.childEntries)
super.removeEntry(entry);
- groupSeparator.optionEntries.clear();
+ groupSeparator.childEntries.clear();
// if no entries, below loop won't run where addEntryBelow() recaches viewable children
if (listOption.options().isEmpty()) {
- recacheViewableChildren();
+ EmptyListLabel emptyListLabel;
+ addEntryBelow(groupSeparator, emptyListLabel = new EmptyListLabel(groupSeparator, category));
+ groupSeparator.childEntries.add(emptyListLabel);
return;
}
@@ -106,7 +117,7 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
for (ListOptionEntry<?> listOptionEntry : listOption.options()) {
OptionEntry optionEntry = new OptionEntry(listOptionEntry, category, listOption, groupSeparator, listOptionEntry.controller().provideWidget(yaclScreen, getDefaultEntryDimension()));
addEntryBelow(lastEntry, optionEntry);
- groupSeparator.optionEntries.add(optionEntry);
+ groupSeparator.childEntries.add(optionEntry);
lastEntry = optionEntry;
}
}
@@ -304,7 +315,7 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
@Override
public boolean isViewable() {
- String query = yaclScreen.searchFieldWidget.getText();
+ String query = yaclScreen.searchFieldWidget.getQuery();
return (groupSeparatorEntry == null || groupSeparatorEntry.isExpanded())
&& (yaclScreen.searchFieldWidget.isEmpty()
|| (!singleCategory && categoryName.contains(query))
@@ -346,7 +357,7 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
protected boolean groupExpanded;
- protected List<OptionEntry> optionEntries;
+ protected List<Entry> childEntries = new ArrayList<>();
private int y;
@@ -401,13 +412,14 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
expandMinimizeButton.setMessage(Text.of(isExpanded() ? "▼" : "▶"));
}
- public void setOptionEntries(List<OptionEntry> optionEntries) {
- this.optionEntries = optionEntries;
+ public void setChildEntries(List<? extends Entry> childEntries) {
+ this.childEntries.clear();
+ this.childEntries.addAll(childEntries);
}
@Override
public boolean isViewable() {
- return yaclScreen.searchFieldWidget.isEmpty() || optionEntries.stream().anyMatch(OptionEntry::isViewable);
+ return yaclScreen.searchFieldWidget.isEmpty() || childEntries.stream().anyMatch(Entry::isViewable);
}
@Override
@@ -506,4 +518,44 @@ public class OptionListWidget extends ElementListWidgetExt<OptionListWidget.Entr
return ImmutableList.of(expandMinimizeButton, addListButton, resetListButton);
}
}
+
+ public class EmptyListLabel extends Entry {
+ private final ListGroupSeparatorEntry parent;
+ private final String groupName;
+ private final String categoryName;
+
+ public EmptyListLabel(ListGroupSeparatorEntry parent, ConfigCategory category) {
+ this.parent = parent;
+ this.groupName = parent.group.name().getString().toLowerCase();
+ this.categoryName = category.name().getString().toLowerCase();
+ }
+
+ @Override
+ public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
+ drawCenteredText(matrices, MinecraftClient.getInstance().textRenderer, Text.translatable("yacl.list.empty").formatted(Formatting.DARK_GRAY, Formatting.ITALIC), x + entryWidth / 2, y, -1);
+ }
+
+ @Override
+ public boolean isViewable() {
+ String query = yaclScreen.searchFieldWidget.getQuery();
+ return parent.isExpanded() && (yaclScreen.searchFieldWidget.isEmpty()
+ || (!singleCategory && categoryName.contains(query))
+ || groupName.contains(query));
+ }
+
+ @Override
+ public int getItemHeight() {
+ return 11;
+ }
+
+ @Override
+ public List<? extends Element> children() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public List<? extends Selectable> selectableChildren() {
+ return ImmutableList.of();
+ }
+ }
}
diff --git a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java b/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java
index 5b7c9dc..3cfe75e 100644
--- a/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java
+++ b/src/client/java/dev/isxander/yacl/gui/SearchFieldWidget.java
@@ -48,6 +48,10 @@ public class SearchFieldWidget extends TextFieldWidget {
yaclScreen.categoryList.setScrollAmount(0);
}
+ public String getQuery() {
+ return getText().toLowerCase();
+ }
+
public boolean isEmpty() {
return isEmpty;
}
diff --git a/src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java
new file mode 100644
index 0000000..314c2ad
--- /dev/null
+++ b/src/client/java/dev/isxander/yacl/impl/LabelOptionImpl.java
@@ -0,0 +1,113 @@
+package dev.isxander.yacl.impl;
+
+import com.google.common.collect.ImmutableSet;
+import dev.isxander.yacl.api.*;
+import dev.isxander.yacl.gui.controllers.LabelController;
+import net.minecraft.text.Text;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.BiConsumer;
+
+public class LabelOptionImpl implements LabelOption {
+ private final Text label;
+ private final Text name = Text.literal("Label Option");
+ private final Text tooltip = Text.empty();
+ private final LabelController labelController;
+ private final Binding<Text> binding;
+
+ public LabelOptionImpl(Text label) {
+ this.label = label;
+ this.labelController = new LabelController(this);
+ this.binding = Binding.immutable(label);
+ }
+
+ @Override
+ public Text label() {
+ return label;
+ }
+
+ @Override
+ public @NotNull Text name() {
+ return name;
+ }
+
+ @Override
+ public @NotNull Text tooltip() {
+ return tooltip;
+ }
+
+ @Override
+ public @NotNull Controller<Text> controller() {
+ return labelController;
+ }
+
+ @Override
+ public @NotNull Binding<Text> binding() {
+ return binding;
+ }
+
+ @Override
+ public boolean available() {
+ return true;
+ }
+
+ @Override
+ public void setAvailable(boolean available) {
+ throw new UnsupportedOperationException("Label options cannot be disabled.");
+ }
+
+ @Override
+ public @NotNull Class<Text> typeClass() {
+ return Text.class;
+ }
+
+ @Override
+ public @NotNull ImmutableSet<OptionFlag> flags() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public boolean changed() {
+ return false;
+ }
+
+ @Override
+ public @NotNull Text pendingValue() {
+ return label;
+ }
+
+ @Override
+ public void requestSet(Text value) {
+
+ }
+
+ @Override
+ public boolean applyValue() {
+ return false;
+ }
+
+ @Override
+ public void forgetPendingValue() {
+
+ }
+
+ @Override
+ public void requestSetDefault() {
+
+ }
+
+ @Override
+ public boolean isPendingValueDefault() {
+ return true;
+ }
+
+ @Override
+ public boolean canResetToDefault() {
+ return false;
+ }
+
+ @Override
+ public void addListener(BiConsumer<Option<Text>, Text> changedListener) {
+
+ }
+}
diff --git a/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java b/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java
index 1924205..fb74601 100644
--- a/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java
+++ b/src/client/java/dev/isxander/yacl/impl/ListOptionImpl.java
@@ -93,7 +93,7 @@ public final class ListOptionImpl<T> implements ListOption<T> {
}
@Override
- public ImmutableList<T> pendingValue() {
+ public @NotNull ImmutableList<T> pendingValue() {
return ImmutableList.copyOf(entries.stream().map(Option::pendingValue).toList());
}