207 lines
7 KiB
Java
207 lines
7 KiB
Java
package net.minecraft.client.gui.components;
|
|
|
|
import java.util.function.Consumer;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.gui.Font;
|
|
import net.minecraft.client.gui.GuiGraphics;
|
|
import net.minecraft.client.gui.components.MultilineTextField.StringView;
|
|
import net.minecraft.client.gui.narration.NarratedElementType;
|
|
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
|
import net.minecraft.client.gui.screens.Screen;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.util.StringUtil;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class MultiLineEditBox extends AbstractTextAreaWidget {
|
|
private static final int CURSOR_INSERT_WIDTH = 1;
|
|
private static final int CURSOR_INSERT_COLOR = -3092272;
|
|
private static final String CURSOR_APPEND_CHARACTER = "_";
|
|
private static final int TEXT_COLOR = -2039584;
|
|
private static final int PLACEHOLDER_TEXT_COLOR = -857677600;
|
|
private static final int CURSOR_BLINK_INTERVAL_MS = 300;
|
|
private final Font font;
|
|
private final Component placeholder;
|
|
private final MultilineTextField textField;
|
|
private long focusedTime = Util.getMillis();
|
|
|
|
public MultiLineEditBox(Font font, int x, int y, int width, int height, Component placeholder, Component message) {
|
|
super(x, y, width, height, message);
|
|
this.font = font;
|
|
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 setValueListener(Consumer<String> valueListener) {
|
|
this.textField.setValueListener(valueListener);
|
|
}
|
|
|
|
public void setValue(String fullText) {
|
|
this.textField.setValue(fullText);
|
|
}
|
|
|
|
public String getValue() {
|
|
return this.textField.value();
|
|
}
|
|
|
|
@Override
|
|
public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
|
|
narrationElementOutput.add(NarratedElementType.TITLE, Component.translatable("gui.narrate.editBox", this.getMessage(), this.getValue()));
|
|
}
|
|
|
|
@Override
|
|
public void onClick(double mouseX, double mouseY) {
|
|
this.textField.setSelecting(Screen.hasShiftDown());
|
|
this.seekCursorScreen(mouseX, mouseY);
|
|
}
|
|
|
|
@Override
|
|
protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) {
|
|
this.textField.setSelecting(true);
|
|
this.seekCursorScreen(mouseX, mouseY);
|
|
this.textField.setSelecting(Screen.hasShiftDown());
|
|
}
|
|
|
|
@Override
|
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
|
return this.textField.keyPressed(keyCode);
|
|
}
|
|
|
|
@Override
|
|
public boolean charTyped(char codePoint, int modifiers) {
|
|
if (this.visible && this.isFocused() && StringUtil.isAllowedChatCharacter(codePoint)) {
|
|
this.textField.insertText(Character.toString(codePoint));
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void renderContents(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
|
String string = this.textField.value();
|
|
if (string.isEmpty() && !this.isFocused()) {
|
|
guiGraphics.drawWordWrap(this.font, this.placeholder, this.getInnerLeft(), this.getInnerTop(), this.width - this.totalInnerPadding(), -857677600);
|
|
} else {
|
|
int i = this.textField.cursor();
|
|
boolean bl = this.isFocused() && (Util.getMillis() - this.focusedTime) / 300L % 2L == 0L;
|
|
boolean bl2 = i < string.length();
|
|
int j = 0;
|
|
int k = 0;
|
|
int l = this.getInnerTop();
|
|
|
|
for (StringView stringView : this.textField.iterateLines()) {
|
|
boolean bl3 = this.withinContentAreaTopBottom(l, l + 9);
|
|
if (bl && bl2 && i >= stringView.beginIndex() && i <= stringView.endIndex()) {
|
|
if (bl3) {
|
|
j = guiGraphics.drawString(this.font, string.substring(stringView.beginIndex(), i), this.getInnerLeft(), l, -2039584) - 1;
|
|
guiGraphics.fill(j, l - 1, j + 1, l + 1 + 9, -3092272);
|
|
guiGraphics.drawString(this.font, string.substring(i, stringView.endIndex()), j, l, -2039584);
|
|
}
|
|
} else {
|
|
if (bl3) {
|
|
j = guiGraphics.drawString(this.font, string.substring(stringView.beginIndex(), stringView.endIndex()), this.getInnerLeft(), l, -2039584) - 1;
|
|
}
|
|
|
|
k = l;
|
|
}
|
|
|
|
l += 9;
|
|
}
|
|
|
|
if (bl && !bl2 && this.withinContentAreaTopBottom(k, k + 9)) {
|
|
guiGraphics.drawString(this.font, "_", j, k, -3092272);
|
|
}
|
|
|
|
if (this.textField.hasSelection()) {
|
|
StringView stringView2 = this.textField.getSelected();
|
|
int m = this.getInnerLeft();
|
|
l = this.getInnerTop();
|
|
|
|
for (StringView stringView3 : this.textField.iterateLines()) {
|
|
if (stringView2.beginIndex() > stringView3.endIndex()) {
|
|
l += 9;
|
|
} else {
|
|
if (stringView3.beginIndex() > stringView2.endIndex()) {
|
|
break;
|
|
}
|
|
|
|
if (this.withinContentAreaTopBottom(l, l + 9)) {
|
|
int n = this.font.width(string.substring(stringView3.beginIndex(), Math.max(stringView2.beginIndex(), stringView3.beginIndex())));
|
|
int o;
|
|
if (stringView2.endIndex() > stringView3.endIndex()) {
|
|
o = this.width - this.innerPadding();
|
|
} else {
|
|
o = this.font.width(string.substring(stringView3.beginIndex(), stringView2.endIndex()));
|
|
}
|
|
|
|
this.renderHighlight(guiGraphics, m + n, l, m + o, l + 9);
|
|
}
|
|
|
|
l += 9;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void renderDecorations(GuiGraphics guiGraphics) {
|
|
super.renderDecorations(guiGraphics);
|
|
if (this.textField.hasCharacterLimit()) {
|
|
int i = this.textField.characterLimit();
|
|
Component component = Component.translatable("gui.multiLineEditBox.character_limit", this.textField.value().length(), i);
|
|
guiGraphics.drawString(this.font, component, this.getX() + this.width - this.font.width(component), this.getY() + this.height + 4, 10526880);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getInnerHeight() {
|
|
return 9 * this.textField.getLineCount();
|
|
}
|
|
|
|
@Override
|
|
protected double scrollRate() {
|
|
return 9.0 / 2.0;
|
|
}
|
|
|
|
private void renderHighlight(GuiGraphics guiGraphics, int minX, int minY, int maxX, int maxY) {
|
|
guiGraphics.fill(RenderType.guiTextHighlight(), minX, minY, maxX, maxY, -16776961);
|
|
}
|
|
|
|
private void scrollToCursor() {
|
|
double d = this.scrollAmount();
|
|
StringView stringView = this.textField.getLineView((int)(d / 9.0));
|
|
if (this.textField.cursor() <= stringView.beginIndex()) {
|
|
d = this.textField.getLineAtCursor() * 9;
|
|
} else {
|
|
StringView stringView2 = this.textField.getLineView((int)((d + this.height) / 9.0) - 1);
|
|
if (this.textField.cursor() > stringView2.endIndex()) {
|
|
d = this.textField.getLineAtCursor() * 9 - this.height + 9 + this.totalInnerPadding();
|
|
}
|
|
}
|
|
|
|
this.setScrollAmount(d);
|
|
}
|
|
|
|
private void seekCursorScreen(double mouseX, double mouseY) {
|
|
double d = mouseX - this.getX() - this.innerPadding();
|
|
double e = mouseY - this.getY() - this.innerPadding() + this.scrollAmount();
|
|
this.textField.seekCursorToPoint(d, e);
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(boolean focused) {
|
|
super.setFocused(focused);
|
|
if (focused) {
|
|
this.focusedTime = Util.getMillis();
|
|
}
|
|
}
|
|
}
|