fix(config-ui-tiny): centralize UI state tracking between individual resets and preset application using a callback to prevent desynchronization
This commit is contained in:
parent
69b8ef894e
commit
261657b2ac
|
@ -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);
|
||||
|
|
|
@ -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 = () -> {
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue