fix(config-ui-tiny): centralize UI state tracking between individual resets and preset application using a callback to prevent desynchronization
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/jfmod Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2023-08-15 13:50:53 +02:00
parent 69b8ef894e
commit 261657b2ac
Signed by: Johannes
GPG Key ID: E76429612C2929F4
4 changed files with 33 additions and 16 deletions

View File

@ -2,13 +2,20 @@ package io.gitlab.jfronny.libjf.config.api.v1.ui.tiny;
import io.gitlab.jfronny.libjf.config.impl.ui.tiny.TinyConfigScreen;
import io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry.Reflowable;
import io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry.WidgetState;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.ClickableWidget;
public interface WidgetFactory {
Widget build(TinyConfigScreen screen, TextRenderer textRenderer);
import java.util.function.Consumer;
public interface WidgetFactory<T> {
Widget<T> build(TinyConfigScreen screen, TextRenderer textRenderer);
record Widget<T>(WidgetState<T> state, Consumer<T> updateControls, ClickableWidget control, Reflowable reflow) implements Reflowable {
public Widget {
state.onUpdateCache(() -> updateControls.accept(state.cachedValue));
}
record Widget(Runnable updateControls, ClickableWidget control, Reflowable reflow) implements Reflowable {
@Override
public void reflow(int width, int height) {
reflow.reflow(width, height);

View File

@ -53,10 +53,7 @@ public class TinyConfigTab implements Tab {
for (WidgetState<?> info : widgets) {
MutableText name = Text.translatable(config.getTranslationPrefix() + info.entry.getName());
WidgetFactory.Widget control = info.factory == null ? null : info.factory.build(screen, textRenderer);
ButtonWidget resetButton = ButtonWidget.builder(Text.translatable("libjf-config-v1.reset"), (button -> {
info.reset();
if (control != null) control.updateControls().run();
}))
ButtonWidget resetButton = ButtonWidget.builder(Text.translatable("libjf-config-v1.reset"), (button -> info.reset()))
.dimensions(screen.width - 155, 0, 40, 20)
.build();
BooleanSupplier resetVisible = () -> {

View File

@ -17,7 +17,6 @@ import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Language;
import java.util.LinkedList;
import java.util.List;
@ -95,7 +94,7 @@ public class EntryInfoWidgetBuilder {
return -1;
}
private static <T> WidgetFactory toggle(EntryInfo<T> info, WidgetState<T> state, UnaryOperator<T> increment, Function<T, Text> valueToText) {
private static <T> WidgetFactory<T> toggle(EntryInfo<T> info, WidgetState<T> state, UnaryOperator<T> increment, Function<T, Text> valueToText) {
return (screen, textRenderer) -> {
final ButtonWidget button = ButtonWidget.builder(valueToText.apply(state.cachedValue), btn -> {
state.updateCache(increment.apply(state.cachedValue));
@ -103,7 +102,7 @@ public class EntryInfoWidgetBuilder {
})
.dimensions(screen.width - 110, 0, info.getWidth(), 20)
.build();
return new WidgetFactory.Widget(() -> button.setMessage(valueToText.apply(state.cachedValue)), button, (width, height) -> button.setX(width - 110));
return new WidgetFactory.Widget<>(state, value -> button.setMessage(valueToText.apply(value)), button, (width, height) -> button.setX(width - 110));
};
}
@ -116,7 +115,7 @@ public class EntryInfoWidgetBuilder {
* @param min The minimum size of a valid value
* @param max The maximum size of a valid value
*/
private static <T> WidgetFactory textField(EntryInfo<T> info, WidgetState<T> state, Pattern pattern, Function<String, Number> sizeFetcher, boolean wholeNumber, double min, double max) {
private static <T> WidgetFactory<T> textField(EntryInfo<T> info, WidgetState<T> state, Pattern pattern, Function<String, Number> sizeFetcher, boolean wholeNumber, double min, double max) {
boolean isNumber = pattern != null;
return (screen, textRenderer) -> {
TextFieldWidget widget = new TextFieldWidget(textRenderer, screen.width - 110, 0, info.getWidth(), 20, null);
@ -150,11 +149,11 @@ public class EntryInfoWidgetBuilder {
return true;
});
return new WidgetFactory.Widget(() -> widget.setText(state.cachedValue == null ? "" : state.cachedValue.toString()), widget, (width, height) -> widget.setX(width - 110));
return new WidgetFactory.Widget<>(state, value -> widget.setText(value == null ? "" : value.toString()), widget, (width, height) -> widget.setX(width - 110));
};
}
private static <T> WidgetFactory jsonScreen(ConfigCategory config, EntryInfo<T> info, WidgetState<T> state) {
private static <T> WidgetFactory<T> jsonScreen(ConfigCategory config, EntryInfo<T> info, WidgetState<T> state) {
state.managedTemp = false;
state.tempValue = null;
return (screen, textRenderer) -> {
@ -201,7 +200,8 @@ public class EntryInfoWidgetBuilder {
})
.dimensions(screen.width - 110, 0, info.getWidth(), 20)
.build();
return new WidgetFactory.Widget(
return new WidgetFactory.Widget<>(
state,
R::nop,
button,
(width, height) -> button.setX(width - 110)
@ -209,7 +209,7 @@ public class EntryInfoWidgetBuilder {
};
}
private static <T extends Number> WidgetFactory slider(EntryInfo info, WidgetState state, Function<T, Double> t2d, Function<Double, T> d2t, boolean wholeNumber) {
private static <T extends Number> WidgetFactory<T> slider(EntryInfo info, WidgetState state, Function<T, Double> t2d, Function<Double, T> d2t, boolean wholeNumber) {
double min = info.getMinValue();
double max = info.getMaxValue();
if (!isDiscrete(min)) throw new IllegalArgumentException("Attempted to create slider with indiscrete minimum");
@ -219,7 +219,7 @@ public class EntryInfoWidgetBuilder {
state.updateCache(d2t.apply(v));
}, wholeNumber);
return new WidgetFactory.Widget(() -> slider.setValue(t2d.apply((T) state.cachedValue)), slider, (width, height) -> slider.setX(width - 110));
return new WidgetFactory.Widget<T>(state, value -> slider.setValue(t2d.apply(value)), slider, (width, height) -> slider.setX(width - 110));
};
}

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry;
import io.gitlab.jfronny.commons.ref.R;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo;
import io.gitlab.jfronny.libjf.config.api.v1.ui.tiny.WidgetFactory;
@ -20,6 +21,8 @@ public class WidgetState<T> {
public T cachedValue;
@Nullable public WidgetFactory factory;
private Runnable onUpdateCache = R::nop;
public void initialize(EntryInfo<T> entry, List<WidgetState<?>> knownStates, @Nullable WidgetFactory factory, String prefix) {
this.entry = entry;
this.knownStates = knownStates;
@ -39,6 +42,15 @@ public class WidgetState<T> {
public void updateCache(T newValue) {
cachedValue = newValue;
if (managedTemp) tempValue = newValue == null ? null : newValue.toString();
onUpdateCache.run();
}
public void onUpdateCache(Runnable action) {
Runnable previous = onUpdateCache;
onUpdateCache = () -> {
previous.run();
action.run();
};
}
public void writeToEntry() throws IllegalAccessException {
@ -47,5 +59,6 @@ public class WidgetState<T> {
public void reset() {
cachedValue = entry.getDefault();
onUpdateCache.run();
}
}