minecraft-src/net/minecraft/client/gui/components/MultiLineLabel.java
2025-09-18 12:27:44 +00:00

219 lines
6.9 KiB
Java

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<MultiLineLabel.TextAndWidth> 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<MultiLineLabel.TextAndWidth> 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<MultiLineLabel.TextAndWidth> 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<MultiLineLabel.TextAndWidth> getSplitMessage() {
Language language = Language.getInstance();
if (this.cachedTextAndWidth != null && language == this.splitWithLanguage) {
return this.cachedTextAndWidth;
} else {
this.splitWithLanguage = language;
List<FormattedText> 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<FormattedText> 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) {
}
}