package net.minecraft.client.gui.components; import java.util.ArrayList; import java.util.List; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.locale.Language; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public interface MultiLineLabel { MultiLineLabel EMPTY = new MultiLineLabel() { @Override public void renderCentered(GuiGraphics guiGraphics, int x, int y) { } @Override public void renderCentered(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { } @Override public void renderLeftAligned(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { } @Override public int renderLeftAlignedNoShadow(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { return y; } @Nullable @Override public Style getStyleAtCentered(int x, int y, int height, double mouseX, double mouseY) { return null; } @Nullable @Override public Style getStyleAtLeftAligned(int x, int y, int height, double mouseX, double mouseY) { return null; } @Override public int getLineCount() { return 0; } @Override public int getWidth() { return 0; } }; static MultiLineLabel create(Font font, Component... components) { return create(font, Integer.MAX_VALUE, Integer.MAX_VALUE, components); } static MultiLineLabel create(Font font, int maxWidth, Component... components) { return create(font, maxWidth, Integer.MAX_VALUE, components); } static MultiLineLabel create(Font font, Component component, int maxWidth) { return create(font, maxWidth, Integer.MAX_VALUE, component); } static MultiLineLabel create(Font font, int maxWidth, int maxRows, Component... components) { return components.length == 0 ? EMPTY : new MultiLineLabel() { @Nullable private List cachedTextAndWidth; @Nullable private Language splitWithLanguage; @Override public void renderCentered(GuiGraphics guiGraphics, int x, int y) { this.renderCentered(guiGraphics, x, y, 9, -1); } @Override public void renderCentered(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { int i = y; for (MultiLineLabel.TextAndWidth textAndWidth : this.getSplitMessage()) { guiGraphics.drawString(font, textAndWidth.text, x - textAndWidth.width / 2, i, color); i += lineHeight; } } @Override public void renderLeftAligned(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { int i = y; for (MultiLineLabel.TextAndWidth textAndWidth : this.getSplitMessage()) { guiGraphics.drawString(font, textAndWidth.text, x, i, color); i += lineHeight; } } @Override public int renderLeftAlignedNoShadow(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color) { int i = y; for (MultiLineLabel.TextAndWidth textAndWidth : this.getSplitMessage()) { guiGraphics.drawString(font, textAndWidth.text, x, i, color, false); i += lineHeight; } return i; } @Nullable @Override public Style getStyleAtCentered(int x, int y, int height, double mouseX, double mouseY) { List list = this.getSplitMessage(); int i = Mth.floor((mouseY - y) / height); if (i >= 0 && i < list.size()) { MultiLineLabel.TextAndWidth textAndWidth = (MultiLineLabel.TextAndWidth)list.get(i); int j = x - textAndWidth.width / 2; if (mouseX < j) { return null; } else { int k = Mth.floor(mouseX - j); return font.getSplitter().componentStyleAtWidth(textAndWidth.text, k); } } else { return null; } } @Nullable @Override public Style getStyleAtLeftAligned(int x, int y, int height, double mouseX, double mouseY) { if (mouseX < x) { return null; } else { List list = this.getSplitMessage(); int i = Mth.floor((mouseY - y) / height); if (i >= 0 && i < list.size()) { MultiLineLabel.TextAndWidth textAndWidth = (MultiLineLabel.TextAndWidth)list.get(i); int j = Mth.floor(mouseX - x); return font.getSplitter().componentStyleAtWidth(textAndWidth.text, j); } else { return null; } } } private List getSplitMessage() { Language language = Language.getInstance(); if (this.cachedTextAndWidth != null && language == this.splitWithLanguage) { return this.cachedTextAndWidth; } else { this.splitWithLanguage = language; List list = new ArrayList(); for (Component component : components) { list.addAll(font.splitIgnoringLanguage(component, maxWidth)); } this.cachedTextAndWidth = new ArrayList(); int i = Math.min(list.size(), maxRows); List list2 = list.subList(0, i); for (int j = 0; j < list2.size(); j++) { FormattedText formattedText = (FormattedText)list2.get(j); FormattedCharSequence formattedCharSequence = Language.getInstance().getVisualOrder(formattedText); if (j == list2.size() - 1 && i == maxRows && i != list.size()) { FormattedText formattedText2 = font.substrByWidth(formattedText, font.width(formattedText) - font.width(CommonComponents.ELLIPSIS)); FormattedText formattedText3 = FormattedText.composite(formattedText2, CommonComponents.ELLIPSIS); this.cachedTextAndWidth.add(new MultiLineLabel.TextAndWidth(Language.getInstance().getVisualOrder(formattedText3), font.width(formattedText3))); } else { this.cachedTextAndWidth.add(new MultiLineLabel.TextAndWidth(formattedCharSequence, font.width(formattedCharSequence))); } } return this.cachedTextAndWidth; } } @Override public int getLineCount() { return this.getSplitMessage().size(); } @Override public int getWidth() { return Math.min(maxWidth, this.getSplitMessage().stream().mapToInt(MultiLineLabel.TextAndWidth::width).max().orElse(0)); } }; } void renderCentered(GuiGraphics guiGraphics, int x, int y); void renderCentered(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color); void renderLeftAligned(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color); int renderLeftAlignedNoShadow(GuiGraphics guiGraphics, int x, int y, int lineHeight, int color); @Nullable Style getStyleAtCentered(int x, int y, int height, double mouseX, double mouseY); @Nullable Style getStyleAtLeftAligned(int x, int y, int height, double mouseX, double mouseY); int getLineCount(); int getWidth(); @Environment(EnvType.CLIENT) public record TextAndWidth(FormattedCharSequence text, int width) { } }