254 lines
9 KiB
Java
254 lines
9 KiB
Java
package net.minecraft.client.gui.screens.dialog;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.function.Supplier;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.components.Button;
|
|
import net.minecraft.client.gui.components.ImageButton;
|
|
import net.minecraft.client.gui.components.ScrollableLayout;
|
|
import net.minecraft.client.gui.components.StringWidget;
|
|
import net.minecraft.client.gui.components.Tooltip;
|
|
import net.minecraft.client.gui.components.WidgetSprites;
|
|
import net.minecraft.client.gui.layouts.GridLayout;
|
|
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
|
|
import net.minecraft.client.gui.layouts.LayoutElement;
|
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
|
import net.minecraft.client.gui.screens.ConfirmScreen;
|
|
import net.minecraft.client.gui.screens.PauseScreen;
|
|
import net.minecraft.client.gui.screens.Screen;
|
|
import net.minecraft.client.gui.screens.dialog.body.DialogBodyHandlers;
|
|
import net.minecraft.commands.Commands;
|
|
import net.minecraft.network.chat.ClickEvent;
|
|
import net.minecraft.network.chat.CommonComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.server.dialog.Dialog;
|
|
import net.minecraft.server.dialog.DialogAction;
|
|
import net.minecraft.server.dialog.Input;
|
|
import net.minecraft.server.dialog.body.DialogBody;
|
|
import org.apache.commons.lang3.mutable.MutableObject;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public abstract class DialogScreen<T extends Dialog> extends Screen {
|
|
public static final Component DISCONNECT = Component.translatable("menu.custom_screen_info.disconnect");
|
|
private static final int WARNING_BUTTON_SIZE = 20;
|
|
private static final WidgetSprites WARNING_BUTTON_SPRITES = new WidgetSprites(
|
|
ResourceLocation.withDefaultNamespace("dialog/warning_button"),
|
|
ResourceLocation.withDefaultNamespace("dialog/warning_button_disabled"),
|
|
ResourceLocation.withDefaultNamespace("dialog/warning_button_highlighted")
|
|
);
|
|
private final T dialog;
|
|
private final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this);
|
|
@Nullable
|
|
private final Screen previousScreen;
|
|
@Nullable
|
|
private ScrollableLayout bodyScroll;
|
|
private Button warningButton;
|
|
private final DialogConnectionAccess connectionAccess;
|
|
private Supplier<Optional<ClickEvent>> onClose = DialogControlSet.EMPTY_ACTION;
|
|
|
|
public DialogScreen(@Nullable Screen previousScreen, T dialog, DialogConnectionAccess connectionAccess) {
|
|
super(dialog.common().title());
|
|
this.dialog = dialog;
|
|
this.previousScreen = previousScreen;
|
|
this.connectionAccess = connectionAccess;
|
|
}
|
|
|
|
@Override
|
|
protected final void init() {
|
|
super.init();
|
|
this.warningButton = this.createWarningButton();
|
|
this.warningButton.setTabOrderGroup(-10);
|
|
DialogControlSet dialogControlSet = new DialogControlSet(this);
|
|
LinearLayout linearLayout = LinearLayout.vertical().spacing(10);
|
|
linearLayout.defaultCellSetting().alignHorizontallyCenter();
|
|
this.layout.addToHeader(this.createTitleWithWarningButton());
|
|
|
|
for (DialogBody dialogBody : this.dialog.common().body()) {
|
|
LayoutElement layoutElement = DialogBodyHandlers.createBodyElement(this, dialogBody);
|
|
if (layoutElement != null) {
|
|
linearLayout.addChild(layoutElement);
|
|
}
|
|
}
|
|
|
|
for (Input input : this.dialog.common().inputs()) {
|
|
dialogControlSet.addInput(input, linearLayout::addChild);
|
|
}
|
|
|
|
this.populateBodyElements(linearLayout, dialogControlSet, this.dialog, this.connectionAccess);
|
|
this.bodyScroll = new ScrollableLayout(this.minecraft, linearLayout, this.layout.getContentHeight());
|
|
this.layout.addToContents(this.bodyScroll);
|
|
this.updateHeaderAndFooter(this.layout, dialogControlSet, this.dialog, this.connectionAccess);
|
|
this.onClose = dialogControlSet.bindAction(this.dialog.onCancel());
|
|
this.layout.visitWidgets(abstractWidget -> {
|
|
if (abstractWidget != this.warningButton) {
|
|
this.addRenderableWidget(abstractWidget);
|
|
}
|
|
});
|
|
this.addRenderableWidget(this.warningButton);
|
|
this.repositionElements();
|
|
}
|
|
|
|
protected void populateBodyElements(LinearLayout layout, DialogControlSet controls, T dialog, DialogConnectionAccess connectionAccess) {
|
|
}
|
|
|
|
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, T dialog, DialogConnectionAccess connectionAccess) {
|
|
}
|
|
|
|
@Override
|
|
protected void repositionElements() {
|
|
this.bodyScroll.setMaxHeight(this.layout.getContentHeight());
|
|
this.layout.arrangeElements();
|
|
this.makeSureWarningButtonIsInBounds();
|
|
}
|
|
|
|
protected LayoutElement createTitleWithWarningButton() {
|
|
LinearLayout linearLayout = LinearLayout.horizontal().spacing(10);
|
|
linearLayout.defaultCellSetting().alignHorizontallyCenter().alignVerticallyMiddle();
|
|
linearLayout.addChild(new StringWidget(this.title, this.font));
|
|
linearLayout.addChild(this.warningButton);
|
|
return linearLayout;
|
|
}
|
|
|
|
protected void makeSureWarningButtonIsInBounds() {
|
|
int i = this.warningButton.getX();
|
|
int j = this.warningButton.getY();
|
|
if (i < 0 || j < 0 || i > this.width - 20 || j > this.height - 20) {
|
|
this.warningButton.setX(Math.max(0, this.width - 40));
|
|
this.warningButton.setY(Math.min(5, this.height));
|
|
}
|
|
}
|
|
|
|
private Button createWarningButton() {
|
|
ImageButton imageButton = new ImageButton(
|
|
0,
|
|
0,
|
|
20,
|
|
20,
|
|
WARNING_BUTTON_SPRITES,
|
|
button -> this.minecraft.setScreen(DialogScreen.WarningScreen.create(this.minecraft, this)),
|
|
Component.translatable("menu.custom_screen_info.button_narration")
|
|
);
|
|
imageButton.setTooltip(Tooltip.create(Component.translatable("menu.custom_screen_info.tooltip")));
|
|
return imageButton;
|
|
}
|
|
|
|
@Override
|
|
public boolean isPauseScreen() {
|
|
return this.dialog.common().pause();
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldCloseOnEsc() {
|
|
return this.dialog.common().canCloseWithEscape();
|
|
}
|
|
|
|
@Override
|
|
public void onClose() {
|
|
this.runAction((Optional<ClickEvent>)this.onClose.get(), DialogAction.CLOSE);
|
|
}
|
|
|
|
public void runAction(Optional<ClickEvent> clickEvent) {
|
|
this.runAction(clickEvent, this.dialog.common().afterAction());
|
|
}
|
|
|
|
public void runAction(Optional<ClickEvent> clickEvent, DialogAction action) {
|
|
Screen screen = (Screen)(switch (action) {
|
|
case NONE -> this;
|
|
case CLOSE -> this.previousScreen;
|
|
case WAIT_FOR_RESPONSE -> new WaitingForResponseScreen(this.previousScreen);
|
|
});
|
|
if (clickEvent.isPresent()) {
|
|
this.handleDialogClickEvent((ClickEvent)clickEvent.get(), screen);
|
|
} else {
|
|
this.minecraft.setScreen(screen);
|
|
}
|
|
}
|
|
|
|
private void handleDialogClickEvent(ClickEvent clickEvent, @Nullable Screen previousScreen) {
|
|
switch (clickEvent) {
|
|
case ClickEvent.RunCommand(String var10):
|
|
this.connectionAccess.runCommand(Commands.trimOptionalPrefix(var10), previousScreen);
|
|
break;
|
|
case ClickEvent.ShowDialog showDialog:
|
|
this.connectionAccess.openDialog(showDialog.dialog(), previousScreen);
|
|
break;
|
|
case ClickEvent.Custom custom:
|
|
this.connectionAccess.sendCustomAction(custom.id(), custom.payload());
|
|
this.minecraft.setScreen(previousScreen);
|
|
break;
|
|
default:
|
|
defaultHandleClickEvent(clickEvent, this.minecraft, previousScreen);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public Screen previousScreen() {
|
|
return this.previousScreen;
|
|
}
|
|
|
|
protected static LayoutElement packControlsIntoColumns(List<? extends LayoutElement> controls, int columns) {
|
|
GridLayout gridLayout = new GridLayout();
|
|
gridLayout.defaultCellSetting().alignHorizontallyCenter();
|
|
gridLayout.columnSpacing(2).rowSpacing(2);
|
|
int i = controls.size();
|
|
int j = i / columns;
|
|
int k = j * columns;
|
|
|
|
for (int l = 0; l < k; l++) {
|
|
gridLayout.addChild((T)((LayoutElement)controls.get(l)), l / columns, l % columns);
|
|
}
|
|
|
|
if (i != k) {
|
|
LinearLayout linearLayout = LinearLayout.horizontal().spacing(2);
|
|
linearLayout.defaultCellSetting().alignHorizontallyCenter();
|
|
|
|
for (int m = k; m < i; m++) {
|
|
linearLayout.addChild((T)((LayoutElement)controls.get(m)));
|
|
}
|
|
|
|
gridLayout.addChild(linearLayout, j, 0, 1, columns);
|
|
}
|
|
|
|
return gridLayout;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static class WarningScreen extends ConfirmScreen {
|
|
private final MutableObject<Screen> returnScreen;
|
|
|
|
public static Screen create(Minecraft minecraft, Screen returnScreen) {
|
|
return new DialogScreen.WarningScreen(minecraft, new MutableObject<>(returnScreen));
|
|
}
|
|
|
|
private WarningScreen(Minecraft minecraft, MutableObject<Screen> returnScreen) {
|
|
super(
|
|
bl -> {
|
|
if (bl) {
|
|
PauseScreen.disconnectFromWorld(minecraft, DialogScreen.DISCONNECT);
|
|
} else {
|
|
minecraft.setScreen(returnScreen.getValue());
|
|
}
|
|
},
|
|
Component.translatable("menu.custom_screen_info.title"),
|
|
Component.translatable("menu.custom_screen_info.contents"),
|
|
CommonComponents.disconnectButtonLabel(minecraft.isLocalServer()),
|
|
CommonComponents.GUI_BACK
|
|
);
|
|
this.returnScreen = returnScreen;
|
|
}
|
|
|
|
@Nullable
|
|
public Screen returnScreen() {
|
|
return this.returnScreen.getValue();
|
|
}
|
|
|
|
public void updateReturnScreen(@Nullable Screen returnScreen) {
|
|
this.returnScreen.setValue(returnScreen);
|
|
}
|
|
}
|
|
}
|