/* * 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 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); } } }