2025-11-24 22:52:51 +03:00

281 lines
12 KiB
Java

/*
* Decompiled with CFR 0.152.
*/
package net.minecraft.client.gui.components;
import com.mojang.blaze3d.platform.cursor.CursorTypes;
import java.util.function.Consumer;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractTextAreaWidget;
import net.minecraft.client.gui.components.MultilineTextField;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.input.CharacterEvent;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.util.ARGB;
import net.minecraft.util.Util;
public class MultiLineEditBox
extends AbstractTextAreaWidget {
private static final int CURSOR_INSERT_WIDTH = 1;
private static final int CURSOR_COLOR = -3092272;
private static final String CURSOR_APPEND_CHARACTER = "_";
private static final int PLACEHOLDER_TEXT_COLOR = ARGB.color(204, -2039584);
private static final int CURSOR_BLINK_INTERVAL_MS = 300;
private final Font font;
private final Component placeholder;
private final MultilineTextField textField;
private final int textColor;
private final boolean textShadow;
private final int cursorColor;
private long focusedTime = Util.getMillis();
private MultiLineEditBox(Font font, int x, int y, int width, int height, Component placeholder, Component narration, int textColor, boolean textShadow, int cursorColor, boolean showBackground, boolean showDecorations) {
super(x, y, width, height, narration, showBackground, showDecorations);
this.font = font;
this.textShadow = textShadow;
this.textColor = textColor;
this.cursorColor = cursorColor;
this.placeholder = placeholder;
this.textField = new MultilineTextField(font, width - this.totalInnerPadding());
this.textField.setCursorListener(this::scrollToCursor);
}
public void setCharacterLimit(int characterLimit) {
this.textField.setCharacterLimit(characterLimit);
}
public void setLineLimit(int lineLimit) {
this.textField.setLineLimit(lineLimit);
}
public void setValueListener(Consumer<String> valueListener) {
this.textField.setValueListener(valueListener);
}
public void setValue(String value) {
this.setValue(value, false);
}
public void setValue(String value, boolean allowOverflowLineLimit) {
this.textField.setValue(value, allowOverflowLineLimit);
}
public String getValue() {
return this.textField.value();
}
@Override
public void updateWidgetNarration(NarrationElementOutput output) {
output.add(NarratedElementType.TITLE, (Component)Component.translatable("gui.narrate.editBox", this.getMessage(), this.getValue()));
}
@Override
public void onClick(MouseButtonEvent event, boolean doubleClick) {
if (doubleClick) {
this.textField.selectWordAtCursor();
} else {
this.textField.setSelecting(event.hasShiftDown());
this.seekCursorScreen(event.x(), event.y());
}
}
@Override
protected void onDrag(MouseButtonEvent event, double dx, double dy) {
this.textField.setSelecting(true);
this.seekCursorScreen(event.x(), event.y());
this.textField.setSelecting(event.hasShiftDown());
}
@Override
public boolean keyPressed(KeyEvent event) {
return this.textField.keyPressed(event);
}
@Override
public boolean charTyped(CharacterEvent event) {
if (!(this.visible && this.isFocused() && event.isAllowedChatCharacter())) {
return false;
}
this.textField.insertText(event.codepointAsString());
return true;
}
@Override
protected void renderContents(GuiGraphics graphics, int mouseX, int mouseY, float a) {
String value = this.textField.value();
if (value.isEmpty() && !this.isFocused()) {
graphics.drawWordWrap(this.font, this.placeholder, this.getInnerLeft(), this.getInnerTop(), this.width - this.totalInnerPadding(), PLACEHOLDER_TEXT_COLOR);
return;
}
int cursor = this.textField.cursor();
boolean showCursor = this.isFocused() && (Util.getMillis() - this.focusedTime) / 300L % 2L == 0L;
boolean insertCursor = cursor < value.length();
int cursorX = 0;
int cursorY = 0;
int drawTop = this.getInnerTop();
boolean hasDrawnCursor = false;
for (MultilineTextField.StringView lineView : this.textField.iterateLines()) {
boolean lineWithinVisibleBounds = this.withinContentAreaTopBottom(drawTop, drawTop + this.font.lineHeight);
int innerLeft = this.getInnerLeft();
if (showCursor && insertCursor && cursor >= lineView.beginIndex() && cursor <= lineView.endIndex()) {
if (lineWithinVisibleBounds) {
substring = value.substring(lineView.beginIndex(), cursor);
graphics.drawString(this.font, substring, innerLeft, drawTop, this.textColor, this.textShadow);
cursorX = innerLeft + this.font.width(substring);
if (!hasDrawnCursor) {
graphics.fill(cursorX, drawTop - 1, cursorX + 1, drawTop + 1 + this.font.lineHeight, this.cursorColor);
hasDrawnCursor = true;
}
graphics.drawString(this.font, value.substring(cursor, lineView.endIndex()), cursorX, drawTop, this.textColor, this.textShadow);
}
} else {
if (lineWithinVisibleBounds) {
substring = value.substring(lineView.beginIndex(), lineView.endIndex());
graphics.drawString(this.font, substring, innerLeft, drawTop, this.textColor, this.textShadow);
cursorX = innerLeft + this.font.width(substring) - 1;
}
cursorY = drawTop;
}
drawTop += this.font.lineHeight;
}
if (showCursor && !insertCursor && this.withinContentAreaTopBottom(cursorY, cursorY + this.font.lineHeight)) {
graphics.drawString(this.font, CURSOR_APPEND_CHARACTER, cursorX + 1, cursorY, this.cursorColor, this.textShadow);
}
if (this.textField.hasSelection()) {
MultilineTextField.StringView selection = this.textField.getSelected();
int drawX = this.getInnerLeft();
drawTop = this.getInnerTop();
for (MultilineTextField.StringView lineView : this.textField.iterateLines()) {
if (selection.beginIndex() > lineView.endIndex()) {
drawTop += this.font.lineHeight;
continue;
}
if (lineView.beginIndex() > selection.endIndex()) break;
if (this.withinContentAreaTopBottom(drawTop, drawTop + this.font.lineHeight)) {
int drawBegin = this.font.width(value.substring(lineView.beginIndex(), Math.max(selection.beginIndex(), lineView.beginIndex())));
int drawEnd = selection.endIndex() > lineView.endIndex() ? this.width - this.innerPadding() : this.font.width(value.substring(lineView.beginIndex(), selection.endIndex()));
graphics.textHighlight(drawX + drawBegin, drawTop, drawX + drawEnd, drawTop + this.font.lineHeight, true);
}
drawTop += this.font.lineHeight;
}
}
if (this.isHovered()) {
graphics.requestCursor(CursorTypes.IBEAM);
}
}
@Override
protected void renderDecorations(GuiGraphics graphics) {
super.renderDecorations(graphics);
if (this.textField.hasCharacterLimit()) {
int characterLimit = this.textField.characterLimit();
MutableComponent countText = Component.translatable("gui.multiLineEditBox.character_limit", this.textField.value().length(), characterLimit);
graphics.drawString(this.font, countText, this.getX() + this.width - this.font.width(countText), this.getY() + this.height + 4, -6250336);
}
}
@Override
public int getInnerHeight() {
return this.font.lineHeight * this.textField.getLineCount();
}
@Override
protected double scrollRate() {
return (double)this.font.lineHeight / 2.0;
}
private void scrollToCursor() {
double scrollAmount = this.scrollAmount();
MultilineTextField.StringView firstFullyVisibleLine = this.textField.getLineView((int)(scrollAmount / (double)this.font.lineHeight));
if (this.textField.cursor() <= firstFullyVisibleLine.beginIndex()) {
scrollAmount = this.textField.getLineAtCursor() * this.font.lineHeight;
} else {
MultilineTextField.StringView lastFullyVisibleLine = this.textField.getLineView((int)((scrollAmount + (double)this.height) / (double)this.font.lineHeight) - 1);
if (this.textField.cursor() > lastFullyVisibleLine.endIndex()) {
scrollAmount = this.textField.getLineAtCursor() * this.font.lineHeight - this.height + this.font.lineHeight + this.totalInnerPadding();
}
}
this.setScrollAmount(scrollAmount);
}
private void seekCursorScreen(double x, double y) {
double mouseX = x - (double)this.getX() - (double)this.innerPadding();
double mouseY = y - (double)this.getY() - (double)this.innerPadding() + this.scrollAmount();
this.textField.seekCursorToPoint(mouseX, mouseY);
}
@Override
public void setFocused(boolean focused) {
super.setFocused(focused);
if (focused) {
this.focusedTime = Util.getMillis();
}
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int x;
private int y;
private Component placeholder = CommonComponents.EMPTY;
private int textColor = -2039584;
private boolean textShadow = true;
private int cursorColor = -3092272;
private boolean showBackground = true;
private boolean showDecorations = true;
public Builder setX(int x) {
this.x = x;
return this;
}
public Builder setY(int y) {
this.y = y;
return this;
}
public Builder setPlaceholder(Component placeholder) {
this.placeholder = placeholder;
return this;
}
public Builder setTextColor(int textColor) {
this.textColor = textColor;
return this;
}
public Builder setTextShadow(boolean textShadow) {
this.textShadow = textShadow;
return this;
}
public Builder setCursorColor(int cursorColor) {
this.cursorColor = cursorColor;
return this;
}
public Builder setShowBackground(boolean showBackground) {
this.showBackground = showBackground;
return this;
}
public Builder setShowDecorations(boolean showDecorations) {
this.showDecorations = showDecorations;
return this;
}
public MultiLineEditBox build(Font font, int width, int height, Component narration) {
return new MultiLineEditBox(font, this.x, this.y, width, height, this.placeholder, narration, this.textColor, this.textShadow, this.cursorColor, this.showBackground, this.showDecorations);
}
}
}