281 lines
12 KiB
Java
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);
|
|
}
|
|
}
|
|
}
|
|
|