minecraft-src/net/minecraft/client/gui/screens/dialog/input/InputControlHandlers.java
2025-09-18 12:27:44 +00:00

205 lines
8 KiB
Java

package net.minecraft.client.gui.screens.dialog.input;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.MapCodec;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractSliderButton;
import net.minecraft.client.gui.components.Checkbox;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.MultiLineEditBox;
import net.minecraft.client.gui.layouts.CommonLayouts;
import net.minecraft.client.gui.layouts.LayoutElement;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.nbt.ByteTag;
import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.server.dialog.action.Action;
import net.minecraft.server.dialog.input.BooleanInput;
import net.minecraft.server.dialog.input.InputControl;
import net.minecraft.server.dialog.input.NumberRangeInput;
import net.minecraft.server.dialog.input.SingleOptionInput;
import net.minecraft.server.dialog.input.TextInput;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@Environment(EnvType.CLIENT)
public class InputControlHandlers {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Map<MapCodec<? extends InputControl>, InputControlHandler<?>> HANDLERS = new HashMap();
private static <T extends InputControl> void register(MapCodec<T> mapCodec, InputControlHandler<? super T> inputControlHandler) {
HANDLERS.put(mapCodec, inputControlHandler);
}
@Nullable
private static <T extends InputControl> InputControlHandler<T> get(T inputControl) {
return (InputControlHandler<T>)HANDLERS.get(inputControl.mapCodec());
}
public static <T extends InputControl> void createHandler(T inputControl, Screen screen, InputControlHandler.Output output) {
InputControlHandler<T> inputControlHandler = get(inputControl);
if (inputControlHandler == null) {
LOGGER.warn("Unrecognized input control {}", inputControl);
} else {
inputControlHandler.addControl(inputControl, screen, output);
}
}
public static void bootstrap() {
register(TextInput.MAP_CODEC, new InputControlHandlers.TextInputHandler());
register(SingleOptionInput.MAP_CODEC, new InputControlHandlers.SingleOptionHandler());
register(BooleanInput.MAP_CODEC, new InputControlHandlers.BooleanHandler());
register(NumberRangeInput.MAP_CODEC, new InputControlHandlers.NumberRangeHandler());
}
@Environment(EnvType.CLIENT)
static class BooleanHandler implements InputControlHandler<BooleanInput> {
public void addControl(BooleanInput booleanInput, Screen screen, InputControlHandler.Output output) {
Font font = screen.getFont();
final Checkbox checkbox = Checkbox.builder(booleanInput.label(), font).selected(booleanInput.initial()).build();
output.accept(checkbox, new Action.ValueGetter() {
@Override
public String asTemplateSubstitution() {
return checkbox.selected() ? booleanInput.onTrue() : booleanInput.onFalse();
}
@Override
public Tag asTag() {
return ByteTag.valueOf(checkbox.selected());
}
});
}
}
@Environment(EnvType.CLIENT)
static class NumberRangeHandler implements InputControlHandler<NumberRangeInput> {
public void addControl(NumberRangeInput numberRangeInput, Screen screen, InputControlHandler.Output output) {
float f = numberRangeInput.rangeInfo().initialSliderValue();
final InputControlHandlers.NumberRangeHandler.SliderImpl sliderImpl = new InputControlHandlers.NumberRangeHandler.SliderImpl(numberRangeInput, f);
output.accept(sliderImpl, new Action.ValueGetter() {
@Override
public String asTemplateSubstitution() {
return sliderImpl.stringValueToSend();
}
@Override
public Tag asTag() {
return FloatTag.valueOf(sliderImpl.floatValueToSend());
}
});
}
@Environment(EnvType.CLIENT)
static class SliderImpl extends AbstractSliderButton {
private final NumberRangeInput input;
SliderImpl(NumberRangeInput numberRangeInput, double d) {
super(0, 0, numberRangeInput.width(), 20, computeMessage(numberRangeInput, d), d);
this.input = numberRangeInput;
}
@Override
protected void updateMessage() {
this.setMessage(computeMessage(this.input, this.value));
}
@Override
protected void applyValue() {
}
public String stringValueToSend() {
return sliderValueToString(this.input, this.value);
}
public float floatValueToSend() {
return scaledValue(this.input, this.value);
}
private static float scaledValue(NumberRangeInput numberRangeInput, double d) {
return numberRangeInput.rangeInfo().computeScaledValue((float)d);
}
private static String sliderValueToString(NumberRangeInput numberRangeInput, double d) {
return valueToString(scaledValue(numberRangeInput, d));
}
private static Component computeMessage(NumberRangeInput numberRangeInput, double d) {
return numberRangeInput.computeLabel(sliderValueToString(numberRangeInput, d));
}
private static String valueToString(float f) {
int i = (int)f;
return i == f ? Integer.toString(i) : Float.toString(f);
}
}
}
@Environment(EnvType.CLIENT)
static class SingleOptionHandler implements InputControlHandler<SingleOptionInput> {
public void addControl(SingleOptionInput singleOptionInput, Screen screen, InputControlHandler.Output output) {
CycleButton.Builder<SingleOptionInput.Entry> builder = CycleButton.<SingleOptionInput.Entry>builder(SingleOptionInput.Entry::displayOrDefault)
.withValues(singleOptionInput.entries())
.displayOnlyValue(!singleOptionInput.labelVisible());
Optional<SingleOptionInput.Entry> optional = singleOptionInput.initial();
if (optional.isPresent()) {
builder = builder.withInitialValue((SingleOptionInput.Entry)optional.get());
}
CycleButton<SingleOptionInput.Entry> cycleButton = builder.create(0, 0, singleOptionInput.width(), 20, singleOptionInput.label());
output.accept(cycleButton, Action.ValueGetter.of((Supplier<String>)(() -> cycleButton.getValue().id())));
}
}
@Environment(EnvType.CLIENT)
static class TextInputHandler implements InputControlHandler<TextInput> {
public void addControl(TextInput textInput, Screen screen, InputControlHandler.Output output) {
Font font = screen.getFont();
LayoutElement layoutElement;
final Supplier<String> supplier;
if (textInput.multiline().isPresent()) {
TextInput.MultilineOptions multilineOptions = (TextInput.MultilineOptions)textInput.multiline().get();
int i = (Integer)multilineOptions.height().orElseGet(() -> {
int ix = (Integer)multilineOptions.maxLines().orElse(4);
return Math.min(9 * ix + 8, 512);
});
MultiLineEditBox multiLineEditBox = MultiLineEditBox.builder().build(font, textInput.width(), i, CommonComponents.EMPTY);
multiLineEditBox.setCharacterLimit(textInput.maxLength());
multilineOptions.maxLines().ifPresent(multiLineEditBox::setLineLimit);
multiLineEditBox.setValue(textInput.initial());
layoutElement = multiLineEditBox;
supplier = multiLineEditBox::getValue;
} else {
EditBox editBox = new EditBox(font, textInput.width(), 20, textInput.label());
editBox.setMaxLength(textInput.maxLength());
editBox.setValue(textInput.initial());
layoutElement = editBox;
supplier = editBox::getValue;
}
LayoutElement layoutElement2 = (LayoutElement)(textInput.labelVisible()
? CommonLayouts.labeledElement(font, layoutElement, textInput.label())
: layoutElement);
output.accept(layoutElement2, new Action.ValueGetter() {
@Override
public String asTemplateSubstitution() {
return StringTag.escapeWithoutQuotes((String)supplier.get());
}
@Override
public Tag asTag() {
return StringTag.valueOf((String)supplier.get());
}
});
}
}
}