[config] Category support pt 2
This commit is contained in:
parent
9b28e3fadb
commit
1964cccf90
@ -0,0 +1,22 @@
|
|||||||
|
package io.gitlab.jfronny.libjf.interfaces;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class Try {
|
||||||
|
public static void orElse(ThrowingRunnable<?> tr, Consumer<Throwable> alternative) {
|
||||||
|
try {
|
||||||
|
tr.run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
alternative.accept(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T orElse(ThrowingSupplier<T, ?> tr, Function<Throwable, T> alternative) {
|
||||||
|
try {
|
||||||
|
return tr.get();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return alternative.apply(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.api;
|
package io.gitlab.jfronny.libjf.config.api;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,9 +14,11 @@ public interface ConfigInstance {
|
|||||||
return ConfigHolder.getInstance().get(modId);
|
return ConfigHolder.getInstance().get(modId);
|
||||||
}
|
}
|
||||||
void load();
|
void load();
|
||||||
|
void write();
|
||||||
|
void loadObject(JsonObject source);
|
||||||
|
JsonObject writeObject();
|
||||||
void syncToClass();
|
void syncToClass();
|
||||||
void syncFromClass();
|
void syncFromClass();
|
||||||
void write();
|
|
||||||
String getModId();
|
String getModId();
|
||||||
boolean matchesConfigClass(Class<?> candidate);
|
boolean matchesConfigClass(Class<?> candidate);
|
||||||
List<EntryInfo> getEntries();
|
List<EntryInfo> getEntries();
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.impl;
|
package io.gitlab.jfronny.libjf.config.impl;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import io.gitlab.jfronny.libjf.LibJf;
|
import io.gitlab.jfronny.libjf.LibJf;
|
||||||
|
import io.gitlab.jfronny.libjf.interfaces.Try;
|
||||||
import io.gitlab.jfronny.libjf.config.api.*;
|
import io.gitlab.jfronny.libjf.config.api.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -12,6 +16,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||||||
public final String modId;
|
public final String modId;
|
||||||
private final String categoryPath;
|
private final String categoryPath;
|
||||||
public final Class<?> configClass;
|
public final Class<?> configClass;
|
||||||
|
private final Constructor<?> configConstructor;
|
||||||
public final List<String> referencedConfigs;
|
public final List<String> referencedConfigs;
|
||||||
public final List<EntryInfo> entries = new ArrayList<>();
|
public final List<EntryInfo> entries = new ArrayList<>();
|
||||||
public final Map<String, Runnable> presets = new LinkedHashMap<>();
|
public final Map<String, Runnable> presets = new LinkedHashMap<>();
|
||||||
@ -21,6 +26,10 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||||||
this.modId = modId;
|
this.modId = modId;
|
||||||
this.categoryPath = categoryPath;
|
this.categoryPath = categoryPath;
|
||||||
this.configClass = configClass;
|
this.configClass = configClass;
|
||||||
|
this.configConstructor = Try.orElse(configClass::getDeclaredConstructor, e -> {
|
||||||
|
LibJf.LOGGER.error("Could not get constructor for config class of " + modId + ", saving will be unavailable", e);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
this.referencedConfigs = List.copyOf(meta.referencedConfigs);
|
this.referencedConfigs = List.copyOf(meta.referencedConfigs);
|
||||||
for (Field field : configClass.getFields()) {
|
for (Field field : configClass.getFields()) {
|
||||||
EntryInfo info = new EntryInfo();
|
EntryInfo info = new EntryInfo();
|
||||||
@ -95,13 +104,48 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
|
|||||||
|
|
||||||
for (Class<?> categoryClass : configClass.getClasses()) {
|
for (Class<?> categoryClass : configClass.getClasses()) {
|
||||||
if (categoryClass.isAnnotationPresent(Category.class)) {
|
if (categoryClass.isAnnotationPresent(Category.class)) {
|
||||||
String path = categoryPath + categoryClass.getSimpleName() + ".";
|
String name = camelCase(categoryClass.getSimpleName());
|
||||||
//TODO allow custom auxiliary metadata
|
//TODO allow custom auxiliary metadata
|
||||||
subcategories.put(path, new ConfigInstanceCategory(this, modId, path, categoryClass, new AuxiliaryMetadata().sanitize()));
|
subcategories.put(name, new ConfigInstanceCategory(this, modId, categoryPath + name + ".", categoryClass, new AuxiliaryMetadata().sanitize()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String camelCase(String source) {
|
||||||
|
if (source == null) return null;
|
||||||
|
if (source.length() == 0) return source;
|
||||||
|
return Character.toLowerCase(source.charAt(0)) + source.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadObject(JsonObject source) {
|
||||||
|
LibJf.GSON.fromJson(source, configClass);
|
||||||
|
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
|
||||||
|
if (source.has(entry.getKey())) {
|
||||||
|
JsonElement el = source.get(entry.getKey());
|
||||||
|
if (el.isJsonObject()) entry.getValue().loadObject(el.getAsJsonObject());
|
||||||
|
else LibJf.LOGGER.error("Config category is not a JSON object, skipping");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject writeObject() {
|
||||||
|
try {
|
||||||
|
if (configConstructor == null) {
|
||||||
|
LibJf.LOGGER.error("Could not save config of " + modId + " due to a missing constructor");
|
||||||
|
return new JsonObject();
|
||||||
|
}
|
||||||
|
JsonObject jo = LibJf.GSON.toJsonTree(configConstructor.newInstance()).getAsJsonObject();
|
||||||
|
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
|
||||||
|
jo.add(entry.getKey(), entry.getValue().writeObject());
|
||||||
|
}
|
||||||
|
return jo;
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Could not access constructor needed to generate config JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncToClass() {
|
public void syncToClass() {
|
||||||
for (EntryInfo info : entries) {
|
for (EntryInfo info : entries) {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.impl;
|
package io.gitlab.jfronny.libjf.config.impl;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
import io.gitlab.jfronny.libjf.LibJf;
|
import io.gitlab.jfronny.libjf.LibJf;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@ -14,17 +18,20 @@ public class ConfigInstanceRoot extends ConfigInstanceAbstract {
|
|||||||
public ConfigInstanceRoot(String modId, Class<?> config, AuxiliaryMetadata meta) {
|
public ConfigInstanceRoot(String modId, Class<?> config, AuxiliaryMetadata meta) {
|
||||||
super(modId, "", config, meta);
|
super(modId, "", config, meta);
|
||||||
path = FabricLoader.getInstance().getConfigDir().resolve(modId + ".json");
|
path = FabricLoader.getInstance().getConfigDir().resolve(modId + ".json");
|
||||||
|
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
try {
|
if (Files.exists(path)) {
|
||||||
LibJf.GSON.fromJson(Files.newBufferedReader(path), configClass);
|
try (BufferedReader br = Files.newBufferedReader(path)) {
|
||||||
|
JsonElement element = JsonParser.parseReader(br);
|
||||||
|
if (element.isJsonObject()) loadObject(element.getAsJsonObject());
|
||||||
|
else LibJf.LOGGER.error("Invalid config: Not a JSON object for " + modId);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
LibJf.LOGGER.error("Could not read config", e);
|
LibJf.LOGGER.error("Could not read config for " + modId, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
syncFromClass();
|
syncFromClass();
|
||||||
write();
|
write();
|
||||||
@ -32,13 +39,12 @@ public class ConfigInstanceRoot extends ConfigInstanceAbstract {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write() {
|
public void write() {
|
||||||
try {
|
|
||||||
JfConfigWatchService.lock(path, () -> {
|
JfConfigWatchService.lock(path, () -> {
|
||||||
if (!Files.exists(path)) Files.createFile(path);
|
try (BufferedWriter bw = Files.newBufferedWriter(path)) {
|
||||||
Files.write(path, LibJf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
LibJf.GSON.toJson(writeObject(), bw);
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LibJf.LOGGER.error("Could not write config", e);
|
LibJf.LOGGER.error("Could not write config", e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.impl;
|
package io.gitlab.jfronny.libjf.config.impl;
|
||||||
|
|
||||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
@ -9,7 +12,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class EntryInfo {
|
public class EntryInfo {
|
||||||
public Field field;
|
public Field field;
|
||||||
public Object widget;
|
public WidgetFactory widget;
|
||||||
public int width;
|
public int width;
|
||||||
public Map.Entry<TextFieldWidget, Text> error;
|
public Map.Entry<TextFieldWidget, Text> error;
|
||||||
public Object defaultValue;
|
public Object defaultValue;
|
||||||
@ -17,4 +20,8 @@ public class EntryInfo {
|
|||||||
public String tempValue;
|
public String tempValue;
|
||||||
public boolean inLimits = true;
|
public boolean inLimits = true;
|
||||||
public Entry entry;
|
public Entry entry;
|
||||||
|
|
||||||
|
public interface WidgetFactory {
|
||||||
|
ClickableWidget build(int width, TextRenderer textRenderer, ButtonWidget done);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.gitlab.jfronny.libjf.config.impl.client.screen;
|
package io.gitlab.jfronny.libjf.config.impl.client.screen;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.libjf.LibJf;
|
||||||
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
|
||||||
import io.gitlab.jfronny.libjf.config.api.Entry;
|
import io.gitlab.jfronny.libjf.config.api.Entry;
|
||||||
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
|
||||||
@ -16,7 +17,6 @@ import net.minecraft.util.Formatting;
|
|||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -34,6 +34,9 @@ public class EntryInfoWidgetBuilder {
|
|||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (ConfigInstance value : config.getCategories().values()) {
|
||||||
|
initConfig(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initEntry(ConfigInstance config, EntryInfo info) {
|
private static void initEntry(ConfigInstance config, EntryInfo info) {
|
||||||
@ -43,25 +46,25 @@ public class EntryInfoWidgetBuilder {
|
|||||||
|
|
||||||
if (info.entry == null) return;
|
if (info.entry == null) return;
|
||||||
|
|
||||||
if (type == int.class || type == Integer.class) textField(config, info, Integer::parseInt, INTEGER_ONLY, info.entry.min(), info.entry.max(), true);
|
if (type == int.class || type == Integer.class) textField(config, info, INTEGER_ONLY, Integer::parseInt, true, info.entry.min(), info.entry.max());
|
||||||
else if (type == float.class || type == Float.class) textField(config, info, Float::parseFloat, DECIMAL_ONLY, info.entry.min(), info.entry.max(),false);
|
else if (type == float.class || type == Float.class) textField(config, info, DECIMAL_ONLY, Float::parseFloat, false, info.entry.min(), info.entry.max());
|
||||||
else if (type == double.class || type == Double.class) textField(config, info, Double::parseDouble, DECIMAL_ONLY, info.entry.min(), info.entry.max(),false);
|
else if (type == double.class || type == Double.class) textField(config, info, DECIMAL_ONLY, Double::parseDouble, false, info.entry.min(), info.entry.max());
|
||||||
else if (type == String.class) textField(config, info, String::length, null, Math.min(info.entry.min(),0), Math.max(info.entry.max(),1),true);
|
else if (type == String.class) textField(config, info, null, String::length, true, Math.min(info.entry.min(),0), Math.max(info.entry.max(),1));
|
||||||
else if (type == boolean.class || type == Boolean.class) {
|
else if (type == boolean.class || type == Boolean.class) {
|
||||||
Function<Object, Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
|
Function<Object, Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
|
||||||
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
|
toggle(info, button -> {
|
||||||
info.value = !(Boolean) info.value;
|
info.value = !(Boolean) info.value;
|
||||||
button.setMessage(func.apply(info.value));
|
button.setMessage(func.apply(info.value));
|
||||||
}, func);
|
}, func);
|
||||||
} else if (type.isEnum()) {
|
} else if (type.isEnum()) {
|
||||||
List<?> values = Arrays.asList(info.field.getType().getEnumConstants());
|
List<?> values = Arrays.asList(info.field.getType().getEnumConstants());
|
||||||
Function<Object,Text> func = value -> new TranslatableText(config.getModId() + ".jfconfig.enum." + type.getSimpleName() + "." + info.value.toString());
|
Function<Object,Text> func = value -> new TranslatableText(config.getModId() + ".jfconfig.enum." + type.getSimpleName() + "." + info.value.toString());
|
||||||
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
|
toggle(info, button -> {
|
||||||
int index = values.indexOf(info.value) + 1;
|
int index = values.indexOf(info.value) + 1;
|
||||||
info.value = values.get(index >= values.size() ? 0 : index);
|
info.value = values.get(index >= values.size() ? 0 : index);
|
||||||
button.setMessage(func.apply(info.value));
|
button.setMessage(func.apply(info.value));
|
||||||
}, func);
|
}, func);
|
||||||
}
|
} else LibJf.LOGGER.error("Invalid entry type in " + info.field.getName() + ": " + type.getName());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
info.value = info.field.get(null);
|
info.value = info.field.get(null);
|
||||||
@ -70,9 +73,26 @@ public class EntryInfoWidgetBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void textField(ConfigInstance config, EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
|
private static void toggle(EntryInfo info, ButtonWidget.PressAction pressAction, Function<Object, Text> valueTextifier) {
|
||||||
|
info.widget = (width, textRenderer, done) -> new ButtonWidget(width - 110, 0, info.width, 20, valueTextifier.apply(info.value), pressAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param config The config this entry is a part of
|
||||||
|
* @param info The entry to generate a widget for
|
||||||
|
* @param pattern The pattern a valid value must abide to
|
||||||
|
* @param sizeFetcher A function to get a number for size constraints
|
||||||
|
* @param wholeNumber Whether size constraints are whole numbers
|
||||||
|
* @param min The minimum size of a valid value
|
||||||
|
* @param max The maximum size of a valid value
|
||||||
|
*/
|
||||||
|
private static void textField(ConfigInstance config, EntryInfo info, Pattern pattern, Function<String, Number> sizeFetcher, boolean wholeNumber, double min, double max) {
|
||||||
boolean isNumber = pattern != null;
|
boolean isNumber = pattern != null;
|
||||||
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
|
info.widget = (width, textRenderer, done) -> {
|
||||||
|
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 110, 0, info.width, 20, null);
|
||||||
|
|
||||||
|
widget.setText(info.tempValue);
|
||||||
|
Predicate<String> processor = s -> {
|
||||||
s = s.trim();
|
s = s.trim();
|
||||||
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
|
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
|
||||||
|
|
||||||
@ -80,22 +100,26 @@ public class EntryInfoWidgetBuilder {
|
|||||||
boolean inLimits = false;
|
boolean inLimits = false;
|
||||||
info.error = null;
|
info.error = null;
|
||||||
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
|
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
|
||||||
value = f.apply(s);
|
value = sizeFetcher.apply(s);
|
||||||
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
|
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
|
||||||
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, new LiteralText(value.doubleValue() < min ?
|
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(widget, new LiteralText(value.doubleValue() < min ?
|
||||||
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
|
"§cMinimum " + (isNumber? "value" : "length") + (wholeNumber ? " is " + (int) min : " is " + min) :
|
||||||
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)));
|
"§cMaximum " + (isNumber? "value" : "length") + (wholeNumber ? " is " + (int) max : " is " + max)));
|
||||||
}
|
}
|
||||||
|
|
||||||
info.tempValue = s;
|
info.tempValue = s;
|
||||||
t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
|
widget.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
|
||||||
info.inLimits = inLimits;
|
info.inLimits = inLimits;
|
||||||
b.active = config.getEntries().stream().allMatch(e -> e.inLimits);
|
done.active = config.getEntries().stream().allMatch(e -> e.inLimits);
|
||||||
|
|
||||||
if (inLimits)
|
if (inLimits)
|
||||||
info.value = isNumber? value : s;
|
info.value = isNumber? value : s;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
widget.setTextPredicate(processor);
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import net.minecraft.client.MinecraftClient;
|
|||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
import net.minecraft.client.gui.screen.ScreenTexts;
|
import net.minecraft.client.gui.screen.ScreenTexts;
|
||||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
import net.minecraft.client.resource.language.I18n;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
@ -19,11 +18,7 @@ import net.minecraft.text.TranslatableText;
|
|||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
//TODO fix missing controls for subcategories
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
public class TinyConfigScreen extends Screen {
|
public class TinyConfigScreen extends Screen {
|
||||||
public TinyConfigScreen(ConfigInstance config, Screen parent) {
|
public TinyConfigScreen(ConfigInstance config, Screen parent) {
|
||||||
@ -73,6 +68,7 @@ public class TinyConfigScreen extends Screen {
|
|||||||
}
|
}
|
||||||
for (EntryInfo info : config.getEntries()) {
|
for (EntryInfo info : config.getEntries()) {
|
||||||
TranslatableText name = new TranslatableText(translationPrefix + info.field.getName());
|
TranslatableText name = new TranslatableText(translationPrefix + info.field.getName());
|
||||||
|
if (info.widget != null) {
|
||||||
ButtonWidget resetButton = new ButtonWidget(width - 155, 0, 40, 20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
|
ButtonWidget resetButton = new ButtonWidget(width - 155, 0, 40, 20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
|
||||||
info.value = info.defaultValue;
|
info.value = info.defaultValue;
|
||||||
info.tempValue = info.value.toString();
|
info.tempValue = info.value.toString();
|
||||||
@ -80,18 +76,7 @@ public class TinyConfigScreen extends Screen {
|
|||||||
Objects.requireNonNull(client).setScreen(this);
|
Objects.requireNonNull(client).setScreen(this);
|
||||||
list.setScrollAmount(scrollAmount);
|
list.setScrollAmount(scrollAmount);
|
||||||
}));
|
}));
|
||||||
|
this.list.addButton(info.widget.build(width, textRenderer, done), resetButton, name);
|
||||||
if (info.widget instanceof Map.Entry) {
|
|
||||||
Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
|
|
||||||
if (info.field.getType().isEnum()) widget.setValue(value -> new TranslatableText(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
|
||||||
this.list.addButton(new ButtonWidget(width - 110, 0, info.width, 20, widget.getValue().apply(info.value), widget.getKey()),resetButton,name);
|
|
||||||
} else if (info.widget != null) {
|
|
||||||
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 110, 0, info.width, 20, null);
|
|
||||||
|
|
||||||
widget.setText(info.tempValue);
|
|
||||||
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done);
|
|
||||||
widget.setTextPredicate(processor);
|
|
||||||
this.list.addButton(widget, resetButton, name);
|
|
||||||
} else {
|
} else {
|
||||||
ButtonWidget dummy = new ButtonWidget(-10, 0, 0, 0, Text.of(""), null);
|
ButtonWidget dummy = new ButtonWidget(-10, 0, 0, 0, Text.of(""), null);
|
||||||
this.list.addButton(dummy,dummy,name);
|
this.list.addButton(dummy,dummy,name);
|
||||||
|
Loading…
Reference in New Issue
Block a user