From 60b7dbe82d8189c22eebcd95a19d0075a127da4e Mon Sep 17 00:00:00 2001 From: JFronny Date: Sun, 13 Aug 2023 18:40:03 +0200 Subject: [PATCH] fix(config-ui-tiny): don't use tabs if they would overflow --- build.gradle.kts | 8 +-- .../config/api/v1/dsl/CategoryBuilder.java | 4 +- .../config/api/v1/dsl/ConfigBuilder.java | 2 + .../config/impl/ui/tiny/TinyConfigScreen.java | 59 ++++++++++++------- .../libjf/config/test/tiny/TestConfig.java | 32 ++++++++++ .../lang/en_us.json | 21 +++++++ .../src/testmod/resources/fabric.mod.json | 17 ++++++ 7 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java create mode 100644 libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json create mode 100644 libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json diff --git a/build.gradle.kts b/build.gradle.kts index 41e58d4..d9b8c27 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,18 +6,18 @@ allprojects { group = "io.gitlab.jfronny.libjf" } -val fabricVersion by extra("0.86.0+1.20.1") +val fabricVersion by extra("0.86.1+1.20.1") val commonsVersion by extra("1.3-SNAPSHOT") val gsonCompileVersion by extra("1.3-SNAPSHOT") -val modmenuVersion by extra("7.0.1") +val modmenuVersion by extra("7.2.1") val annotationsVersion by extra("24.0.1") val javapoetVersion by extra("1.13.0") jfMod { minecraftVersion = "1.20.1" - yarn("build.9") - loaderVersion = "0.14.21" + yarn("build.10") + loaderVersion = "0.14.22" modrinth { projectId = "libjf" diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java index fa9c7b0..45378fa 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java @@ -1,7 +1,6 @@ package io.gitlab.jfronny.libjf.config.api.v1.dsl; -import io.gitlab.jfronny.gson.JsonElement; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.SamWithReceiver; import io.gitlab.jfronny.libjf.config.api.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import org.jetbrains.annotations.ApiStatus; @@ -46,6 +45,7 @@ public interface CategoryBuilder> { ConfigCategory build(Supplier root); @FunctionalInterface + @SamWithReceiver interface CategoryBuilderFunction { CategoryBuilder apply(CategoryBuilder builder); } diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java index d52ca10..f7755ff 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/ConfigBuilder.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.libjf.config.api.v1.dsl; +import io.gitlab.jfronny.commons.SamWithReceiver; import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance; import java.nio.file.Path; @@ -18,6 +19,7 @@ public interface ConfigBuilder> extends C ConfigInstance build(); @FunctionalInterface + @SamWithReceiver interface ConfigBuilderFunction { ConfigBuilder apply(ConfigBuilder builder); } diff --git a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java b/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java index 1c0e729..882ef53 100644 --- a/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java +++ b/libjf-config-ui-tiny-v1/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreen.java @@ -11,6 +11,7 @@ import io.gitlab.jfronny.libjf.config.impl.ui.tiny.presets.PresetsScreen; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.ScreenRect; import net.minecraft.client.gui.screen.Screen; @@ -18,10 +19,10 @@ import net.minecraft.client.gui.tab.TabManager; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TabNavigationWidget; import net.minecraft.client.resource.language.I18n; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; import java.util.*; @@ -32,7 +33,7 @@ public class TinyConfigScreen extends Screen { if (JfConfigSafe.TRANSLATION_SUPPLIER.apply(titlePath) != null) { return Text.translatable(titlePath); } - final String alternatePath = categoryPath.length() == 0 ? "" : categoryPath.substring(0, categoryPath.length() - 1); + final String alternatePath = categoryPath.isEmpty() ? "" : categoryPath.substring(0, categoryPath.length() - 1); if (JfConfigSafe.TRANSLATION_SUPPLIER.apply(alternatePath) != null) { return Text.translatable(alternatePath); } @@ -44,6 +45,7 @@ public class TinyConfigScreen extends Screen { private final Placeholder placeholder; private final TabManager tabManager = new TabManager(a -> selectTab(((TinyConfigTabWrapper)a).getTab()), a -> {}); private List tabs; + private final boolean considerTabs; public ButtonWidget done; private boolean reload = false; @@ -53,6 +55,10 @@ public class TinyConfigScreen extends Screen { this.config = config; this.widgets = new LinkedList<>(); this.placeholder = new Placeholder<>(null); + + this.considerTabs = config.getEntries().isEmpty() + && config.getPresets().keySet().stream().allMatch(s -> s.equals(CategoryBuilder.CONFIG_PRESET_DEFAULT)) + && config.getReferencedConfigs().isEmpty(); } @Override @@ -75,22 +81,10 @@ public class TinyConfigScreen extends Screen { }) .dimensions(this.width / 2 + 4, this.height - 28, 150, 20) .build(); - - if (config.getEntries().isEmpty() - && config.getPresets().keySet().stream().allMatch(s -> s.equals(CategoryBuilder.CONFIG_PRESET_DEFAULT)) - && config.getReferencedConfigs().isEmpty() - ) { - this.tabs = config.getCategories() - .values() - .stream() - .map(c -> new TinyConfigTab(this, c, textRenderer, false)) - .toList(); - } else { - this.tabs = List.of(); - } - if (this.tabs.isEmpty()) this.tabs = List.of(new TinyConfigTab(this, config, textRenderer, true)); } else done.setPosition(width / 2 + 4, height - 28); + updateTabs(); + TabNavigationWidget tabNavigation = TabNavigationWidget.builder(tabManager, this.width) .tabs(tabs.toArray(TinyConfigTab[]::new)) .build(); @@ -121,6 +115,35 @@ public class TinyConfigScreen extends Screen { reload = true; } + private boolean wasTabs = false; + private void updateTabs() { + boolean useTabs = considerTabs && !tabsWouldOverflow(config.getCategories().values()); + if (reload) { + if (!considerTabs) return; + if (wasTabs == useTabs) return; + } + wasTabs = useTabs; + + tabs = !useTabs ? List.of() : config.getCategories() + .values() + .stream() + .map(c -> new TinyConfigTab(this, c, textRenderer, false)) + .toList(); + if (tabs.isEmpty()) tabs = List.of(new TinyConfigTab(this, config, textRenderer, true)); + } + + private boolean tabsWouldOverflow(Collection categories) { + int tabNavWidth = this.width; + int headerWidth = Math.min(400, tabNavWidth) - 28; + int singleHeaderWidth = MathHelper.roundUpToMultiple(headerWidth / categories.size(), 2); + int singleTextWidth = singleHeaderWidth - 2; + TextRenderer tr = MinecraftClient.getInstance().textRenderer; + for (ConfigCategory category : categories) { + if (tr.getWidth(getTitle(category.getTranslationPrefix())) > singleTextWidth) return true; + } + return false; + } + public void afterSelectPreset() { for (WidgetState widget : widgets) { widget.updateCache(); @@ -169,8 +192,4 @@ public class TinyConfigScreen extends Screen { public MinecraftClient getClient() { return Objects.requireNonNull(client); } - - public boolean hasClient() { - return client != null; - } } diff --git a/libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java b/libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java new file mode 100644 index 0000000..6238207 --- /dev/null +++ b/libjf-config-ui-tiny-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/tiny/TestConfig.java @@ -0,0 +1,32 @@ +package io.gitlab.jfronny.libjf.config.test.tiny; + +import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig; +import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL; + +public class TestConfig implements JfCustomConfig { + private int value1 = 0; + private String value2 = ""; + private boolean value3 = false; + private int value4 = 0; + private String value5 = ""; + private boolean value6 = false; + + @Override + public void register(DSL.Defaulted dsl) { + dsl.register(builder -> builder + .category("ca1", builder1 -> builder1 + .value("value1", value1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, () -> value1, v -> value1 = v) + ).category("ca2", builder1 -> builder1 + .value("value2", value2, () -> value2, v -> value2 = v) + ).category("ca3", builder1 -> builder1 + .value("value3", value3, () -> value3, v -> value3 = v) + ).category("ca4", builder1 -> builder1 + .value("value4", value4, -5, 12, () -> value4, v -> value4 = v) + ).category("ca5", builder1 -> builder1 + .value("value5", value5, () -> value5, v -> value5 = v) + ).category("ca6", builder1 -> builder1 + .value("value6", value6, () -> value6, v -> value6 = v) + ) + ); + } +} diff --git a/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json b/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json new file mode 100644 index 0000000..3191f81 --- /dev/null +++ b/libjf-config-ui-tiny-v1/src/testmod/resources/assets/libjf-config-ui-tiny-v1-testmod/lang/en_us.json @@ -0,0 +1,21 @@ +{ + "libjf-config-ui-tiny-v1-testmod.jfconfig.title": "JfConfig example", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.title": "Category 1", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.tooltip": "This is category 1", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca1.value1": "Value 1", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.title": "Category 2", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.tooltip": "This is category 2", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca2.value1": "Value 2", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.title": "Category 3", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.tooltip": "This is category 3", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca3.value1": "Value 3", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.title": "Category 4", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.tooltip": "This is category 4", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca4.value1": "Value 4", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.title": "Category 5", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.tooltip": "This is category 5", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca5.value1": "Value 5", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.title": "Category 6", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.tooltip": "This is category 6", + "libjf-config-ui-tiny-v1-testmod.jfconfig.ca6.value1": "Value 6" +} \ No newline at end of file diff --git a/libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json b/libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..e3315aa --- /dev/null +++ b/libjf-config-ui-tiny-v1/src/testmod/resources/fabric.mod.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "id": "libjf-config-ui-tiny-v1-testmod", + "name": "LibJF Config UI: Tiny", + "version": "1.0", + "environment": "*", + "entrypoints": { + "libjf:config": [ + "io.gitlab.jfronny.libjf.config.test.tiny.TestConfig" + ] + }, + "custom": { + "modmenu": { + "parent": "libjf-testmod" + } + } +} \ No newline at end of file